UIKit

UIListContentConfiguration, UIBackgroundConfiguration, UICellConfigurationState

Phililip
728x90

안녕하세요.

 

우연히 봤는데, UITableViewCell에서 textLabel, detailTextLabel, imageView가 deprecated 되었더라구요?

 

 

 

들어가서 보니, contentConfiguration이라는 것을 사용하라고 합니다.

 

 

(WWDC20) Modern cell configuration을 보면서 뭔지 공부해볼게요.

 

 


 

## UIListContentConfiguration

iOS 13 이하에서는 아래처럼 cell의 built-in imageView, textLabel 사용했어요.

class ViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
    let data = ["star", "folder", "person", "tray"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.dataSource = self
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.imageView?.image = UIImage(systemName: data[indexPath.row])  ✅
        cell.textLabel?.text = data[indexPath.row]
        return cell
    }
}

 

 

 

 

iOS 14부턴 UIListContentConfiguration이란 것을 사용해주면 됩니다. 위의 작업을 아래처럼 구현할 수 있게 됩니다.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell()
    
    // cell.imageView?.image = UIImage(systemName: data[indexPath.row])
    // cell.textLabel?.text = data[indexPath.row]
    
    var content = cell.defaultContentConfiguration()  ✅
    content.image = UIImage(systemName: data[indexPath.row])  ✅
    content.text = data[indexPath.row]  ✅
    cell.contentConfiguration = content  ✅
    
    return cell
}

 

cell의 defaultContentConfiguration을 가져오고,

 

configuration에 추가 설정을 해준 뒤에,

 

cell에 적용시킨다는 개념이에요.

 

Q. defaultContentConfiguration이 뭔데?

A. 현재 List 뷰의 스타일과 cell을 기반으로 기본 style이 적용된 UIContentConfiguration을 리턴해줍니다.
이때, 스타일에 대한 기본값들만 설정되어 있고 content에 대한 것은 포함되어 있지 않으니 주의해주세요.

 

 

이처럼 UIListContentConfiguration을 사용하면 화면에 어떤 내용(content)을 넣을 것이냐 에 대한 설정을 쉽게 할 수 있어요.

(이름에 Content가 들어가 있는 것만 봐도 알겠죠?)

 

출처: https://developer.apple.com/videos/play/wwdc2020/10027/

 

 

 

 

## UIBackgroundConfiguration

UIListContentConfiguration은 content 설정에 관한 것이었다면, UIBackgroundConfiguration을 사용하면 background 설정을 쉽게 해 줄 수 있습니다. (배경색, stroke, cornerRadius 등)

 

출처: https://developer.apple.com/videos/play/wwdc2020/10027/

 

 

예를 들어볼게요.

 

우선 시스템 기본 스타일 중 하나를 골라서 UIBackgroundConfiguration을 생성해주고

var backgroundConfig = UIBackgroundConfiguration.listPlainCell()

 

이것저것 설정해준 다음,

backgroundConfig.backgroundColor = .yellow
backgroundConfig.strokeWidth = 5
backgroundConfig.strokeColor = .blue
backgroundConfig.cornerRadius = 10

 

cell에 적용시켜주면 됩니다. (꼭 cell이 아니어도 UIButton, Header, Footer 같은 것들에도 적용할 수 있어요.)

cell.backgroundConfiguration = backgroundConfig

 

아래는 전체 코드입니다.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell()

    var content = cell.defaultContentConfiguration()
    content.image = UIImage(systemName: data[indexPath.row])
    content.text = data[indexPath.row]
    cell.contentConfiguration = content

    var backgroundConfig = UIBackgroundConfiguration.listPlainCell()  ✅
    backgroundConfig.backgroundColor = .yellow
    backgroundConfig.strokeWidth = 5
    backgroundConfig.strokeColor = .blue
    backgroundConfig.cornerRadius = 10
    cell.backgroundConfiguration = backgroundConfig

    return cell
}

 

 

결과물을 볼까요??

 

 

간단하고 직관적인 코드로 쉽게 설정할 수 있게 된 점은 매우 좋은 것 같습니다ㅎㅎ

 

 

 

 

## UICellConfigurationState

UICellConfigurationState는 cell state를 캡슐화한 구조체를 말합니다.

 

여기서 cell state란, 현재 cell이 선택되었는지 swipe 되었는지 와 같은 cell의 상태를 의미합니다.

 

 

보통 UICellConfigurationState를 직접 만들지는 않구요,

 

cell state에 따른 추가 동작을 시켜주고 싶을 경우, cell subclass의 updateConfiguration(using:) method를 override 해서 UICellConfigurationState를 얻습니다.

 

 

 

직접 해볼까요?

 

우선 cell subclass를 만들어주고 text, image가 저장될 프로퍼티를 만들어줄게요.

class MyCell: UITableViewCell {
    var title: String!
    var image: UIImage!
}

 

 

그다음 updateConfiguration(using:) method를 override 할게요.

(parameter에 UICellConfigurationState가 있는 것 보이시나요??ㅎㅎ cell state를 알기 위해서 요걸 사용할 거예요.)

class MyCell: UITableViewCell {
    var title: String!
    var image: UIImage!
    
    override func updateConfiguration(using state: UICellConfigurationState) {
        
    }
}

 

그다음 updateConfiguration method 안에서 defaultContentConfiguration().updated(for: state) method를 호출해서 기본 ContentConfiguration을 가져옵니다.

 

Q. defaultContentConfiguration()이 아닌 defaultContentConfiguration().updated(for: state)인 이유?

A. 현재 상태에 대한 system default styling이 적용된 ContentConfiguration을 얻기 위해서 updated(for: state) method를 추가로 호출해준 것입니다.

 

class MyCell: UITableViewCell {
    var title: String!
    var image: UIImage!
    
    override func updateConfiguration(using state: UICellConfigurationState) {
        var content = self.defaultContentConfiguration().updated(for: state)  ✅
    }
}

 

 

cell에 text, image를 설정해주고,

class MyCell: UITableViewCell {
    var title: String!
    var image: UIImage!
    
    override func updateConfiguration(using state: UICellConfigurationState) {
        var content = self.defaultContentConfiguration().updated(for: state)
        
        content.text = self.title   ✅
        content.image = self.image  ✅
    }
}

 

 

cell이 선택되었을 때 text와 image를 바뀌도록 해볼게요.

class MyCell: UITableViewCell {
    var title: String!
    var image: UIImage!
    
    override func updateConfiguration(using state: UICellConfigurationState) {
        var content = self.defaultContentConfiguration().updated(for: state)
        
        content.text = self.title
        content.image = self.image
        
        if state.isSelected {  ✅
            content.text = "Selected"
            content.image = UIImage(systemName: "checkmark")
        }
    }
}

 

 

마지막으로 설정한 Content Configuration을 cell에 적용시켜주세요.

class MyCell: UITableViewCell {
    var title: String!
    var image: UIImage!
    
    override func updateConfiguration(using state: UICellConfigurationState) {
        var content = self.defaultContentConfiguration().updated(for: state)
        
        content.text = self.title
        content.image = self.image
        
        if state.isSelected {
            content.text = "Selected"
            content.image = UIImage(systemName: "checkmark")
        }

        self.contentConfiguration = content  ✅
    }
}

 

 

사용하는 곳(ex. ViewController)에서는 MyCell 객체를 생성해서 반환만 해주면 됩니다.

(Cell 설정들이 MyCell 안에 있으니까 ViewController에서는 신경 쓸 필요가 없는 것이죠.)

class ViewController: UIViewController, UITableViewDataSource {
    ...
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = MyCell()  ✅
        cell.title = data[indexPath.row]
        cell.image = UIImage(systemName: data[indexPath.row])!
        return cell
    }
}

 

 

😁 😁 😁

 

 

만약에 나는 subclass 만드는 것도 귀찮다!! 하는 경우라면, configurationUpdateHandler를 사용하셔도 상관없습니다.

(생각보다 쉽죠??ㅎㅎ)

class ViewController: UIViewController, UITableViewDataSource {
    ...
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()

        cell.configurationUpdateHandler = { [weak self] cell, state in  ✅
            var content = cell.defaultContentConfiguration().updated(for: state)
            content.text = self?.data[indexPath.row]
            content.image = UIImage(systemName: (self?.data[indexPath.row])!)
            
            if state.isSelected {
                content.text = "Selected"
                content.image = UIImage(systemName: "checkmark")
            }
            
            cell.contentConfiguration = content
        }
        
        return cell
    }
}

 

 

 

## 참고

- https://developer.apple.com/videos/play/wwdc2020/10027/

- https://developer.apple.com/documentation/uikit/uilistcontentconfiguration

- https://developer.apple.com/documentation/uikit/uibackgroundconfiguration

- https://developer.apple.com/documentation/uikit/uicellconfigurationstate

- https://developer.apple.com/documentation/uikit/uicollectionviewcell/3600950-updateconfiguration

- https://developer.apple.com/documentation/uikit/uitableviewcell/3750915-configurationupdatehandler

- https://zeddios.tistory.com/1205?category=682195 

- https://zeddios.tistory.com/1206?category=682195 

- https://medium.com/swlh/ios-14-modern-cell-configuration-for-beginners-programmatically-2a1be3f12a90

 

 


 

이번 글은 여기서 마무리.

 

 

 

반응형

'UIKit' 카테고리의 다른 글

viewDidLayoutSubviews  (0) 2022.07.24
UIKeyboardLayoutGuide  (0) 2022.03.29
Image 비동기 로딩 API (UIKit)  (0) 2022.03.23
DiffableDataSource를 사용해서 TableView 드래그&드롭 기능 넣기  (0) 2022.02.19
DiffableDataSource  (0) 2022.02.19