관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] UIButton 하나로 토글 버튼 구현 방법 (+ RxSwift, RxCocoa, isHighlighted, withLatestFrom) 본문

iOS 기본 (swift)

[iOS - swift] UIButton 하나로 토글 버튼 구현 방법 (+ RxSwift, RxCocoa, isHighlighted, withLatestFrom)

jake-kim 2022. 4. 26. 23:43

UIButton하나로 구현된 토글 버튼 (재생, 중지)

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)

* 전체 코드: https://github.com/JK0369/ExToggleButton

Comments