iOS 응용 (swift)
[iOS - swift] UITableViewCell에 pressed 효과 주는 방법 (highlighted 효과, pressed 효과)
jake-kim
2024. 10. 24. 01:42
UITableViewCell의 pressed 효과
- 기대하는 pressed 효과 (이 화면은 pressed 효과를 직접 구현한 화면)
- UIButton의 highlighted 효과처럼 동작
- 하지만 위처럼 동작하려면 별도 구현이 필요하고, 디폴트는 이렇게 동작됨
- 단, selectionStyle = .none으로 한 상태
코드)
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
cell.myLabel.text = "Row \(indexPath.row)"
return cell
}
}
class CustomTableViewCell: UITableViewCell {
private enum Const {
static let backgroundColor = UIColor.white
static let pressedColor = UIColor.gray
}
let myLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
contentView.addSubview(myLabel)
NSLayoutConstraint.activate([
myLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
myLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
pressed 효과 주는 방법
- 우선 커스텀 셀에 setHighlighted를 오버라이딩하여 backgroundColor를 변경
class CustomTableViewCell: UITableViewCell {
...
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
contentView.backgroundColor = highlighted ? Const.pressedColor : Const.backgroundColor
}
...
}
결과)
- long pressed 한 상태에서만 색상이 변경됨
- UIButton과 다르게 UITableViewCell은 setHighlighted 호출 시점이 long pressed 시점
- 터치했을때도 pressed 효과가 발동해야하므로 didSelectRowAt 델리게이트 함수에서 별도로 pressed 효과를 발생시키기
- 커스텀 셀 내부에 pressed 애니메이션 구현
class CustomTableViewCell: UITableViewCell {
...
func animatePressed(completion: @escaping () ->()) {
contentView.backgroundColor = Const.pressedColor
UIView.animate(withDuration: 0.3, animations: {
self.contentView.backgroundColor = Const.backgroundColor
self.layoutIfNeeded()
}, completion: { _ in
completion()
})
}
...
}
- 이 함수를 didSelectRowAt에서 호출
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
(tableView.cellForRow(at: indexPath) as? CustomTableViewCell)?.animatePressed {
// no-op
}
}
}
완성)
전체 코드)
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.frame = view.bounds
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
cell.myLabel.text = "Row \(indexPath.row)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
(tableView.cellForRow(at: indexPath) as? CustomTableViewCell)?.animatePressed {
// no-op
}
}
}
class CustomTableViewCell: UITableViewCell {
private enum Const {
static let backgroundColor = UIColor.white
static let pressedColor = UIColor.gray
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
contentView.backgroundColor = highlighted ? Const.pressedColor : Const.backgroundColor
}
let myLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = .black
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
contentView.addSubview(myLabel)
NSLayoutConstraint.activate([
myLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
myLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16)
])
}
func animatePressed(completion: @escaping () ->()) {
contentView.backgroundColor = Const.pressedColor
UIView.animate(withDuration: 0.3, animations: {
self.contentView.backgroundColor = Const.backgroundColor
self.layoutIfNeeded()
}, completion: { _ in
completion()
})
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}