iOS 기본 (swift)
[iOS - swift] UIButton 하나로 토글 버튼 구현 방법 (+ RxSwift, RxCocoa, isHighlighted, withLatestFrom)
jake-kim
2022. 4. 26. 23:43
UIButton 하나로 토글 버튼 구현 방법
- UIButton에는 normal, selected, highlighted가 존재
- normal과 selected 상태를 이용하여 토글 버튼으로 활용
- highlighted애니메이션은 setImage(_:for:) 에서 for부분에 적용
- normal -> highlighted 애니메이션은 for: .highlighted로 설정
- selecte -> highlighted 애니메이션은 배열로 선언 [.selected, .highlighted]
button.setImage(UIImage(named: "play"), for: .normal)
button.setImage(UIImage(named: "play-pressed"), for: .highlighted)
button.setImage(UIImage(named: "stop"), for: .selected)
button.setImage(UIImage(named: "stop-pressed"), for: [.selected, .highlighted])
RxSwift, RxCocoa를 사용하여 버튼 처리
- Button의 isHighlighted 상태를 구독하여, isSelected 상태를 토글의 상태로 파악하고 적용
- isHighlighted, isSelected를 Rx Extension 추가
extension Reactive where Base: UIControl {
public var isHighlighted: Observable<Bool> {
self.base.rx.methodInvoked(#selector(setter: self.base.isHighlighted))
.compactMap { $0.first as? Bool }
.startWith(self.base.isHighlighted)
.distinctUntilChanged()
.share()
}
public var isSelected: Observable<Bool> {
self.base.rx.methodInvoked(#selector(setter: self.base.isSelected))
.compactMap { $0.first as? Bool }
.startWith(self.base.isSelected)
.distinctUntilChanged()
.share()
}
}
- 버튼의 상태관리를 위해서 computed proprety로 observable 정의
- onPlayButtonPressed: isHighlighted를 받았을 때 withLatestFrom 연산자로 isSelected 상태를 받아서 현재 상태 확인
private var onPlayButtonPressed: Observable<Bool> {
self.button.rx.isHighlighted
.filter { $0 == true }
.withLatestFrom(self.button.rx.isSelected)
.map { !$0 }
}
var playButtonTapObservable: Observable<Void> {
self.onPlayButtonPressed
.filter { $0 == false }
.map { _ in return Void() }
.asObservable()
}
var stopButtonTapObservable: Observable<Void> {
self.onPlayButtonPressed
.filter { $0 == true }
.map { _ in return Void() }
.asObservable()
}
- 버튼이 탭 될때마다 selected상태를 변경해주어야 하므로, onPlayButtonPressed를 구독하여 처리
self.onPlayButtonPressed
.bind(to: self.button.rx.isSelected)
.disposed(by: self.disposeBag)