Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIL] iOS 15이상 버튼 #20

Open
samsung-ga opened this issue Jul 6, 2022 · 4 comments
Open

[TIL] iOS 15이상 버튼 #20

samsung-ga opened this issue Jul 6, 2022 · 4 comments

Comments

@samsung-ga
Copy link
Owner

samsung-ga commented Jul 6, 2022

UIKit button system

버튼은 iOS앱을 개발하면서 빼먹을 수 없는 UI 요소이다. 앱의 버튼은 정말 여러가지 형태로 존재한다. 이미지와 텍스트가 삽입되거나 삽입되지 않은 버튼, 다양한 색깔로 이루어진 버튼 등등..

이번에 프로젝트를 진행하며 커스텀 버튼을 만드는 역할을 맡았다. 이전에는 버튼을 항상 커스텀해서 만들었다면 이번에는 WWDC21에서 발표한 새로운 Button System을 이용해서 만들어보고 싶어서 알아보기로 했다.
아래 글은 WWDC21 - Meet the UI button system 영상을 참고하여 작성한 내용이다.

iOS 15에선 UIKit은 4가지 스타일의 버튼을 제공한다.
기본적으로 알고 있었던 버튼 + gray, tinted, filled 스타일이 추가되었다. (bordered 타입은 따로 존재.)스타일 뿐만 아니라 아래의 기능들도 추가되었다.

  • Dynamic type
  • Multiline
  • Accessibility
  • Easier cutomization

Dynamic type은 레이아웃을 더 자유자재로 조절할 수 있을 것 같고, multiline은 한 줄만으로 이루어졌던 버튼을 여러 줄로 이루어질 수 있게끔 해주는 기능같다. accessibility는 더 접근성을 높였다는 내용이고, 마지막은 버튼의 커스터마이즈가 더 쉬워졌다는 내용인 것 같다. 커스터마이즈가 더 쉬워졌다니..!! 이제 커스텀 버튼을 안만들어도되는 것일까! ㅎㅎ

UIButton의 스타일에 대해 먼저 알아보자.

UIButtonConfiguration

이제는 configuration을 이용해 버튼을 초기화한다. 물론 쓰지 않고 초기화가 가능하다. 아래는 버튼을 초기화할 수 있는 많은 생성자이다.


스크린샷 2022-07-07 오전 12 17 35

button configuration으로 조절 가능한 버튼의 스타일에는 다음과 같은 것들이 있다.

  • 버튼 타입
  • 버튼 텍스트
  • 이미지
  • 이미지 위치
  • activityIndicator 기능
  • 버튼 레이아웃 구성 (모두 default값에서 증가만 가능)
    • contentInsets
    • imagePadding
    • titlePadding

스크린샷 2022-07-06 오후 5 19 19

  • Semantic 스타일 제공
    • UI 관련
      • baseBackgroundColor
      • baseForegroundColor
      • cornerStyle
      • buttonSize
    • 기능 관련
      • normal
      • pressed
      • disabled

Configuration을 이용해 버튼을 생성하는 방법 중 하나이다. primaryAction에 대해서는 아래에서 알아보자.

var config = UIButton.Configuration.tinted()
config.title = "Add to Cart"
config.image = UIImage(systemName: "cart.badge.plus")
config.imagePlacement = .trailing
addToCartButton = UIButton(configuration: config,
                           primaryAction: )

button configuration 종류에도 아래와 같은 종류들이 있다. 나중에 하나씩 둘러보자.

스크린샷 2022-07-07 오전 12 58 26



configurationUpdateHandler

버튼이 눌렸을 때, 업데이트하고 싶은 상황이 있다. 예를 들어, 다른 작업때문에 버튼의 스타일을 정의하는 configuration이 바뀌어야 할 때, 이 프로퍼티를 사용한다.

  1. 기존 configuration을 가져온다.
  2. 업데이트한다.
  3. 새로운 configuration 재적용한다.

*만약 버튼의 속성이 아닌 값이 변경될 때 configurationUpdateHandler가 업데이트되게 하기 위해서 setNeedsUpdateConfiguration()을 불러준다.

아래는 isCartBusy 프로퍼티에 의해서 버튼이 activityIndicator를 보여주는 예제이다. (외부 작업에 의해 버튼의 configuration이 수정됨)

var config = UIButton.Configuration.filled()
config.buttonSize = .large
config.image = UIImage(systemName: "cart.fill")
config.title = "Checkout"
config.background.backgroundColor = .buttonEmporium

let checkoutButton = UIButton(configuration: config
                              primaryAction: …) 
addToCartButton.configurationUpdateHandler = {
    [unowned self] button in

    var config = button.configuration
	  // ✅ isCartBusy이 바뀌면 setNeedsUpdateConfiguration을 호출
    config?.showsActivityIndicator = self.isCartBusy 
    button.configuration = config
}


버튼의 기능

푸쉬 기능

  • 너무 당연한 이야기라 넘어가자!

토글 기능

  • on/off 기능

스크린샷 2022-07-07 오전 12 23 45 스크린샷 2022-07-07 오전 12 23 56

changesSelectionAsPrimaryAction 프로퍼티를 이용하여 토글 기능을 구현한다.

let stockToggleAction = UIAction(title: "In Stock Only") { _ in
    toggleStock()
}

// The button
let button = UIButton(primaryAction: stockToggleAction)

button.changesSelectionAsPrimaryAction = true

// Initial state
button.isSelected = showingOnlyInStock()

Pop-up

image 스크린샷 2022-07-07 오전 12 27 58

// Pop-up button

let colorClosure = { (action: UIAction) in
    updateColor(action.title)
}

let button = UIButton(primaryAction: nil)

button.menu = UIMenu(children: [
    UIAction(title: "Bondi Blue", handler: colorClosure),
    UIAction(title: "Flower Power", state: .on, handler: colorClosure)
])

button.showsMenuAsPrimaryAction = true

button.changesSelectionAsPrimaryAction = true

// Update to the currently set one
updateColor(button.menu?.selectedElements.first?.title)

// Update the selection
(button.menu?.children[selectedColorIndex()] as? UIAction)?.state = .on


UIAction

기존에는 @objc#selector를 이용해서 버튼이 눌렸을 때의 action을 코드로 구현해주어야 했다면 새로운 생성자에서는 UIAction를 사용하면 된다.

//  ✅ 기존 방법 
let button1 = UIButton(type: .system)
button1.translatesAutoresizingMaskIntoConstraints = false
button1.addTarget(self, action: #selector(button1Pressed), for: .touchUpInside)

@objc private func button1Pressed() {

 }
//  ✅ UIAction 사용
let action = UIAction(title: "button2") { (action: UIAction) in
        // 터치
        print("터치", action.title)
}
let button2 = UIButton(configuration: configuration, primaryAction: action)


UIAction 생성자엔 여러 변수들을 초기화할 수 있다. title과 image를 초기화하고 버튼이 생성될 때 configuration을 넣는다면 해당 title과 image를 가진 버튼이 생성된다.

안되는 버그같은 스펙들 (더 찾아봐야함)

결론 (😿)

커스텀이 더욱 쉬워질 것이라고 영상에서 발표하였지만 조금 사용해본 후기로는 딱히 커스텀이 편해진 것 같지 않다. 더 사용해보아야겠지만 커스텀이 원하는만큼 되지 않는다면 이번 프로젝트에서도 커스텀 버튼을 만들어야 할 것 같다.

@samsung-ga samsung-ga added in progress issue which is in progress UIKit labels Jul 6, 2022
@samsung-ga
Copy link
Owner Author

toggle과 popup을 사용한 예제 추가

@samsung-ga
Copy link
Owner Author

configuration을 이용해서 내가 원하는 스타일의 custom button을 만들어본 후기 -> 실패 예상

@samsung-ga samsung-ga removed the in progress issue which is in progress label Jul 6, 2022
@samsung-ga
Copy link
Owner Author

어느 정도 만들 수 있었다.

@chaneeii
Copy link

shadow 는 기존과 동일하게 주면되나요...?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants