UIButton.isSelected/isEnabled issue

이번 포스팅은 UIButton의 isSelected, isEnabled 를 같이 사용하며 있었던 이슈를 기록해놓기 위해 작성한 포스팅이에요 :)

구현

코드

lazy var editButton: UIButton = {
    button.isSelected = false
    button.setTitle("편집", for: .normal)
    button.setTitle("전체 읽음", for: .selected)
    button.setTitleColor(.black, for: .normal)
    button.setTitleColor(.black, for: .selected)
    button.setTitleColor(.gray, for: .disabled)
    return button
}()

코드의 의도

editButton 은 normal 상태와 selected 상태별로 다른 문구의 타이틀을 가지고, 상태값에 따라 설정된 타이틀을 표시하는 버튼을 만드려고 했어요.

그리고 추가로, 버튼이 isEnabled 상태가 되면 버튼 타이틀 색상을 Black에서 Gray로 변경 될 수 있도록 의도했어요.

실제로 의도와 예상되는 동작 결과에 맞게 버튼은 상태값에 따라 타이틀 문구가 변경되고 색상 또한 Black에서 Gray로 변경되는 것을 확인했어요.

문제 발생

// editButton이 Tap 되었을때
editButton.rx.tap
    .withUnretained(self)
    // editButton.isSelected == false일 경우에만
    .filter { !$0.0.editButton.isSelected }
    .subscribe(onNext: { owner, _ in
    	// editButton.isSelected = true 로 변경
        owner.editButton.isSelected = true
        // editButton.isEnabled를 isAllReadable 값으로 변경
        owner.editButton.isEnabled = owner.isAllReadable
    })
    .disposed(by: rx.disposeBag)

isSelected 가 false일 때만 filter에 의해 걸러지기 때문에, 버튼의 타이틀은 현재 “전체 읽음” 상태라는 것을 의미해요.

문제 1.

true로 변경해주기 때문에 “편집” -> “전체 읽음” 으로 변경 되어야 하는데 “편집” 상태에서 변경되지 않아요.

하지만, 브레이크 포인트를 통해 로그를 찍어보면 isSelected 값은 true로 정상적으로 출력되는 것을 볼 수 있었어요.

문제2.

isEnabled 값에 의해 버튼 타이틀의 색상이 Gray 또는 Black으로 변경되지 않았어요.

문제3.

owner.editButton.isSelected = true 또는

owner.editButton.isEnabled = owner.isAllReadable

isSelectedisEnabled 프로퍼티를 변경하는 코드 둘 중 하나를 지워주면(또는 주석) 정상적으로 타이틀 문구와 색상이 변경이 돼요.(왜죠..?)

문제4.

owner.editButton.isSelected의 값을 true가 아닌 false로 설정하는 코드에서는 정상적으로 타이틀 문구와 색상이 변경돼요.

해결 방법

혹시나 공식 문서나 스택오버 플로우에서 isSelected, isEnabled 를 같이 사용하면 발생하는 이슈가 있는것은 아닌지 찾아보고, 혹시 isEnabled가 먼저 동작하면서 isSelected가 동작하는 것은 아닌지 찾아보는 등.. 시행착오와 검색을 반복하다가 아래와 같은 방법으로 수정하기로 정했어요!

editButton.rx.tap
    .withUnretained(self)
    .filter { !$0.0.editButton.isSelected }
    .subscribe(onNext: { owner, _ in
        owner.editButton.isSelected = true
        owner.enableEditButton(isEnabled: owner.isEditable)
    })
    .disposed(by: rx.disposeBag)
private func enableEditButton(isEnabled: Bool) {
    let state: UIControl.State = editButton.isSelected ? .selected : .normal
    editButton.setTitleColor(isEnabled ? .black : .gray, for: state)
    editButton.isUserInteractionEnabled = isEnabled ? true : false
}

isEnabled 프로퍼티를 사용하지 않고, 버튼 상태값에 따라 setTitleColor(_:) 메서드를 호출하여 타이틀 컬러값을 변경해주고 isUserInteractionEnabled 프로퍼티 값을 변경하여 버튼의 사용자 상호작용을 비활성화 했어요!

의도했던 코드가 의도했던대로 동작하지 않을 때, 항상 그 문제로 deep dive 해볼 수 있는 시간이 있다면 좋겠지만 때로는 시간적 여유가 허락되지 않을때가 있을 수 있어요.

이럴땐, 자신이 의도했던 동작은 무엇인지, 문제가 되는 것은 무엇인지, 어떻게 해결할 수 있을지를 빠르게 파악하고 해결해나가는 능력 또한 중요하다는 것을 알 수 있어요 :)

Categories:

Updated:

Leave a comment