공부

WWDC 21 ) Meet the UIKit button system

Zedd0202 2021. 7. 4. 18:33
반응형

 

안녕하세요 :) Zedd입니다.

오늘은 iOS 15에서 굉장히 많이 업데이트가 된 UIButton들에 대해서 알아보겠습니다 👀

Meet the UIKit  button system을 아주 빠르고 간단하게 요약해보겠습니다.

 

# Deprecated property/method in UIButton

영상에는 나오진 않지만...iOS 15에서 UIButton에 deprecated property/method가 많아졌습니다.

(Xcode 13 Beta 2기준입니다.) 

reversesTitleShadowWhenHighlighted

adjustsImageWhenHighlighted

adjustsImageWhenDisabled

showsTouchWhenHighlighted

contentEdgeInsets

titleEdgeInsets

imageEdgeInsets

backgroundRect(forBounds:)

contentRect(forBounds:)

titleRect(forContentRect:)

imageRect(forContentRect:)

 

adjustsImageWhenHighlighted 와 titleEdgeInsets 이런것들은 많이 썼는데... deprecate되다니! 

참고하세요!

 

# What's New in UIButton 

Xcode 12, 13 순입니다. 

앞구르기 하면서 봐도 뭔가 Button 스타일이 늘어난 것을 볼 수 있는데요. 

1. Plain, Gary, Tinted, Filled 스타일의 버튼이 추가되었습니다. (왼쪽 그림)

2. multiline text가 지원됩니다. (오른쪽 그림)

3. Dynamic Type을 기본적으로 지원합니다. 

3번에 대해서 추가설명을 하자면..

Xcode 12, 13 순

Xcode 13 이전에서 Button을 추가하면 왼쪽 그림처럼 System 15.0으로 지정되어있어서 

기본적으로 Dynamic Type 지원이 안됐었어요. 

Xcode 13에서는 중간, 오른쪽 그림처럼 IB에서 Font설정이 아예 다 빠지고, Dynamic Type을 기본적으로 지원합니다.

4. subtitle을 지원합니다. 

5. activity indicator를 지원합니다.

 

# Configuration

이 Button들은 각각 다른 Button이 아니라 다 UIButton입니다.

let button = UIButton(type: .system)
button.configuration = .filled() ✅

이렇게 configuration으로 설정이 가능합니다.

버튼에 타이틀을 줘봅시다.

button.setTitle("대충 타이틀", for: .normal) ✅

이렇게들 사용하실텐데요, 이제는 Configuration으로도 쌉가능한 부분이 되었습니다.

var configuration = UIButton.Configuration.tinted()
configuration.title = "대충 타이틀"
let button = UIButton(configuration: configuration, primaryAction: ...)

[결과]

 configuration으로 정말 많은것들을 설정할 수 있는데 

title, subtitle, attributedTitle, attributedSubtitle, titlePadding, titleAlignment, image....등을 설정할 수 있습니다. 

var configuration = UIButton.Configuration.tinted()
configuration.image = UIImage(systemName: "heart")
configuration.imagePlacement = .trailing
configuration.subtitle = "대충 서브타이틀"
configuration.title = "대충 타이틀"
let button = UIButton(configuration: configuration, primaryAction: nil)

imagePlacement도 지정할 수 있다는거!

타이틀이랑 이미지 사이의 간격이 너무 좁네요,, 역시나 imagePadding도 있습니다.

var configuration = UIButton.Configuration.tinted()
configuration.image = UIImage(systemName: "heart")
configuration.imagePlacement = .trailing
configuration.imagePadding = 30 ✅
configuration.subtitle = "대충 서브타이틀"
configuration.title = "대충 타이틀"
let button = UIButton(configuration: configuration, primaryAction: nil)

titlePadding과 imagePadding은 왼쪽 그림을 참고해주세요. 

 

# ConfigurationUpdateHandler

버튼 누름 → 오른쪽 그림처럼 Image가 변경되었으면 좋겠음.

그럴 때 ConfigurationUpdateHandler를 사용하면 됩니다.

button.configurationUpdateHandler = { button in
      var config = button.configuration
      config?.image = button.isHighlighted ? UIImage(systemName: "heart.fill") : UIImage(systemName: "heart")
      button.configuration = config
}

이렇게요!

지금은 이미지만 업데이트 했지만..Configration에 있는 어떤 프로퍼티든 업데이트가 가능합니다.

[🚨주의🚨]

isHighlighted는 UIButton의 State이므로 해당 값이 변경될 때 ConfigurationUpdateHandler가 호출됩니다. 

외부에 flag라는 변수가 있고, 다른 버튼에서 flag를 업데이트 해줍니다.

let secondButton = UIButton(configuration: secondConfig, primaryAction: UIAction(handler: { action in
            self.flag.toggle()
}))

그리고 ConfigurationUpdateHandler에서 해당 flag값을 보고 이미지를 업데이트 해줍니다. 

button.configurationUpdateHandler = { button in
      var config = button.configuration
      config?.image = ✅ self.flag ✅ ? UIImage(systemName: "heart.fill") : UIImage(systemName: "heart")
      button.configuration = config
}

이렇게요.이렇게하면 ConfigurationUpdateHandler는 불리지 않는데요.

button의 state가 변경되지 않았기 때문입니다.

 

[ConfigurationUpdateHandler 호출하게 만드는 방법]

var flag = false {
      didSet {
            self.button.setNeedsUpdateConfiguration()
      }
}

flag의 값이 변경되면, setNeedsUpdateConfiguration를 호출하게하면 됩니다. 

그럼 대충 이렇게됨 

 

# UIButton. 근데 이제 Activity Indicator를 곁들인

위에서도 잠깐 언급했지만 이제 Button에 Activity Indicator를 보여줄 수 있습니다. 

showActivityIndicator만 true로 하기만 하면 됩니다.

(필요한 경우 이미지를 대체하기도 합니다.) 

참고로 showActivityIndicator는 Configuration에 있는 프로퍼티이므로

configuration.showsActivityIndicator = true 

이렇게 해주면 됩니다.

showActivityIndicator는 ConfigurationUpdateHandler안에 있으면 좋을 것 같네요.

 

# Semantic styling

semaintic styling을 사용하면 위와같은 프로퍼티 변경 후 추가적인 작업없이 오른쪽과 같은 state별 상태를 가지게 됩니다.

해당 프로퍼티들은 Configuration안에 있습니다.

 

# Pull Down Button / Pop Up button

Pull Down Button과 Pop Up Button도 라이브러리에 추가되었는데요.

Pull Down Button은 이번에 추가된건 아니고..iOS 14에 추가된 menu라고 보시면 됩니다. 

관련 글은 iOS 14 + ) UIMenu on UIButton 를 참고해주세요

대충 이런겁니다...

그럼 Pop Up Button만 보면 되겠군요@!

Pop Up Button은 Pull Down Button과 비슷한데, 메뉴 요소중 하나만 선택되도록 한다는 것이 차이점입니다.

이렇게! 

기존 Pull Down Button에서 

let favorite = UIAction(title: "즐겨찾기", image: UIImage(systemName: "heart"), handler: { _ in print("즐겨찾기") })

let cancel = UIAction(title: "취소", attributes: .destructive, handler: { _ in print("취소") })
self.button.menu = UIMenu(title: "title입니다",
                     image: UIImage(systemName: "heart.fill"),
                     identifier: nil,
                     options: .displayInline,
                     children: [favorite, cancel])
self.button.showsMenuAsPrimaryAction = true ✅
self.button.changesSelectionAsPrimaryAction = true ✅

아래 두 코드만 추가해주면 됩니다.

타이틀도 알아서 바뀜...

 

아무도 안궁금할 것 같지만..제가 헷갈려서 씀

🙋 : ㅇ ㅑ!!!! iOS 14 + ) UIMenu on UIButton 에서

이렇게 체크표시 할 수 있었잖아.

Pull Down Button이랑 Pop Up Button이랑 다른게 좀 헷갈리는데..둘 다 똑같은거 아녀? 

🧑‍💻 : 맞습니다! 

let favorite = UIAction(title: "즐겨찾기", image: UIImage(systemName: "heart"), ✅ state: .on ✅ ,handler: { _ in print("즐겨찾기") })

state를 on으로 하면 왼쪽에 체크표시가 나왔었죠.

만약 action모두에 state를 on하면 위 오른쪽 그림처럼 체크 표시가 여러개 나올 수도 있었습니다. 

하지만,

self.button.changesSelectionAsPrimaryAction = true // iOS 15부터 사용 가능 

changesSelectionAsPrimaryAction를 true로 주게 되면 

두 Action모두 state가 on이었어도 

self.button.changesSelectionAsPrimaryAction = true // iOS 15부터 사용 가능 

self.button.menu = UIMenu(title: "title입니다",
                     image: UIImage(systemName: "heart.fill"),
                     identifier: nil,
                     options: .displayInline,
                     children: [favorite, cancel]) ✅

여기에 먼저 추가된 것만 체크표시가 나게 됩니다. 지금은 favorite이 cancel보다 앞에 있으니

즐겨찾기가 체크 된 채로 나오게 됩니다. 

만약 이 코드가 없다면

self.button.changesSelectionAsPrimaryAction = true // iOS 15부터 사용 가능 

왼쪽 그림처럼 둘다 state가 on인 상태이니 둘 다 체크표시가 나오게 되고,

아까 오른쪽 gif처럼 Button title이 자동으로 바뀌지도 않게 됩니다.

 

# 그 외

영상에 나오진 않지만, 그냥 참고하면 좋은것들..

- Style은 IB에서 지정이 가능합니다. 

- Corner Style도 IB에서 지정이 가능합니다. 

[Fixed, Dynamic]

Dynamic Type에 따라 Corner Style을 조정하냐의 차이입니다.

Fixed / Dynamic

[그 외]

small / medium / large / Capsule

 

참고 : 

Meet the UIKit  button system

반응형