WWDC2021가 발표한지는 한참 지났지만, 정리해보는 UIButton,
iOS15.0의 버튼이 특별히 달라지는 것은 아니지만, 기존에 서브클래싱 등으로 해결해야 했던것을 Configuration
을 통해 제공해주는 것이 핵심이다.
iOS15.0 UIButton은 기본 4가지 스타일을 제공한다.
전통적인 UIButton은 다음과 같을 것이다.
let button = UIButton(type: .system)
button.setTitle("Sign In", for: [])
여기에 Basic Style을 적용하는 방법은 아래와 같다.
let button = UIButton(type: .system)
button.setTitle("Sign In", for: [])
button.configuration = .filled()
Basic Style을 적용해서 BackgroundColor
Tint와CornerRadius
가 있는 버튼을 빠르게 얻을 수 있다.
바닐라 스타일을 사용하는 사람들에게는 편리한 기능으로 보인다.
UIButton 인스턴스를 생성 한 후에, 프로퍼티들을 바꾸는 것이 아니라, UIButton.Configuration을 미리 만들고, UIButton 인스턴스를 만들 때 configuration을 생성자에 전달할 수 있다.
이 방법은 굳이 UIButton을 서브클래싱 하는 것보다 더 나은 재사용성을 누릴 수 있다.
위 예제에서는 button을 생성 한 뒤에, 타이틀을 입력했지만 configuration을 사용하면 아래와 같이 할 수 있다.
var config = UIButton.Configuration.tinted()
config.title = "Hello, Swift!"
config.image = UIImage(systemName: "swift")
let button = UIButton(
configuration: config,
primaryAction: UIAction(handler: { _ in
print("Hello, Swift!")
}))
configuration에는 다양한 옵션이 있기 때문에 입맛대로 사용하기도 편하다.
예를들어서 이미지 위치가 왼쪽이 아니라 오른쪽에 위치했으면 좋겠다고 한다면
config.imagePlacement = .trailing
이 한출 추가하는 것으로 이미지는 오른쪽으로 이동한다.
이 외에도 타이틀과 이미지의 패딩, 타이틀의 정렬 기준 등등 다양하기 때문에 문서를 보고 사용해 보길 권장
Button을 사용하다보면, 항상 똑같은 모습을 보여주는 정적인 버튼 말고도, 상태에 따라 변하는 동적인 버튼을 많이 사용한다.
기존에는 버튼 상태를 나타내는 모델에서 모델이 변경되면 버튼을 업데이트 하도록 구성할 수 있었다.
button.configurationUpdateHandler = { [unowned self] button in
var config = button.configuration
config?.title = "오늘의 할일"
config?.image = self.done
? UIImage(systemName: "checkmark.square.fill")
: UIImage(systemName: "square")
config?.subtitle = self.done
? "01/16 Done!"
: "01/16"
button.configuration = config
}
button.setNeedsUpdateConfiguration()
setNeedsUpdateConfiguration()
을 호출해서, 버튼 UI의 갱신상태를 변경 요청할 수 있다.
Button.Configuration
은 이외에도 다양하고 유용한 기능을 제공한다.
기존에 UIButton에 Activity Indicator를 이용하려면 서브클래싱을 통해서 해야했는데 Button.Configuration에 이 기능이 들어갔다.
var loggin: Bool = false {
didSet {
button.setNeedsUpdateConfiguration()
button.isEnabled = !loggin
}
}
button.configurationUpdateHandler = { [unowned self] button in
var config = button.configuration
config?.title = "Sign In"
config?.showsActivityIndicator = loggin
config?.image = UIImage(systemName: "externaldrive.connected.to.line.below")
button.configuration = config
}
func requestLoggin() {
loggin = true
//Network Request Code
DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
self.loggin = false
}
}
configurationUpdateHandler()
에 showActivityIndicator
만 설정해 주면 된다.
예를들어서 로그인을 요청하면 서버에서 응답이 올때까지 버튼에 인디케이터가 표시 되어야 하는 경우, 다음 과 같이 코드를 작성할 수 있다.
버튼의 On/Off 상태를 좀더 편리하게 사용해주는 새 기능으로 해당 프로퍼티를 true로 설정하게 되면 버튼 선택에 따른 상태를 얻을 수 있다.
button.changesSelectionAsPrimaryAction = true
changeSelectionAsPrimaryAction
을 true로 하면 버튼 토글 상태가 button.isSelected
로 전달된다.
맨 위에서 했던 예제로 다시 돌아가자면
button.changesSelectionAsPrimaryAction = true
button.configurationUpdateHandler = { button in
var config = button.configuration
config?.title = "오늘의 할일"
config?.image = button.isSelected
? UIImage(systemName: "checkmark.square.fill")
: UIImage(systemName: "square")
config?.subtitle = button.isSelected
? "01/16 Done!"
: "01/16"
button.configuration = config
}
버튼의 상태를 isSelected로 선택해볼 수 있다.
버튼을 구성할 때 팝업 버튼 형식으로 쓰고 싶을 때는 showMenuAsPrimaryAction
을 true
로 두기만 하면 된다.
button.showsMenuAsPrimaryAction = true
button.menu = UIMenu(children: [
UIAction(title: "삭제하기", attributes: .destructive, handler: deleteComment),
UIAction(title: "수정하기", handler: editComment)
])
만약 팝업 버튼 안에서 토글 방식이 필요하다면 changeSelectionAsPrimaryAction
을 true로 두면 팝업 안에서 토글 형식으로 쓸 수 있다
button.showsMenuAsPrimaryAction = true
button.menu = UIMenu(children: [
UIAction(title: "매일반복", handler: repeatEveryday),
UIAction(title: "요일반복", handler: repeatDay)
])
button.changesSelectionAsPrimaryAction = true
각 예제 프로젝트는 TIL에서 보실 수 있습니다.
https://github.com/urijan44/TIL-Store/tree/master/iOS_Swift/UIKit/UIButtonConfiguration.playground