|
1 | | -import SnapKit |
2 | 1 | import UIKit |
3 | 2 |
|
| 3 | +import Infrastructure |
| 4 | + |
| 5 | +import SnapKit |
| 6 | +import Then |
| 7 | + |
4 | 8 | final class BalloonChipCell: UICollectionViewCell { |
5 | | - static let identifier = "BalloonChipCell" |
6 | | - |
7 | | - private let button: PPButton = { |
8 | | - let button = PPButton( |
9 | | - style: .secondary, |
10 | | - text: "", |
11 | | - font: .korFont(style: .medium, size: 11), |
12 | | - cornerRadius: 15 |
13 | | - ) |
14 | | - |
15 | | - button.titleLabel?.lineBreakMode = .byTruncatingTail |
16 | | - button.titleLabel?.adjustsFontSizeToFitWidth = false |
17 | | - return button |
18 | | - }() |
19 | | - |
20 | | - override init(frame: CGRect) { |
21 | | - super.init(frame: frame) |
22 | | - contentView.addSubview(button) |
23 | | - setupLayout() |
24 | | - } |
25 | | - |
26 | | - required init?(coder: NSCoder) { |
27 | | - fatalError("init(coder:) has not been implemented") |
28 | | - } |
29 | | - |
30 | | - private func setupLayout() { |
31 | | - button.snp.makeConstraints { make in |
32 | | - make.edges.equalToSuperview() |
33 | | - } |
34 | | - } |
35 | | - |
36 | | - func configure(with title: String, isSelected: Bool) { |
37 | | - button.setTitle(title, for: .normal) |
38 | | - if isSelected { |
39 | | - let checkImage = UIImage(named: "icon_check_white")?.withRenderingMode(.alwaysOriginal) |
40 | | - let resizedImage = checkImage?.resize(to: CGSize(width: 16, height: 16)) |
41 | | - button.setImage(resizedImage, for: .normal) |
42 | | - button.semanticContentAttribute = .forceRightToLeft |
43 | | - button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 2, bottom: 0, right: 0) |
44 | | - button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 10, bottom: 6, right: 12) |
45 | | - button.setBackgroundColor(.blu500, for: .normal) |
46 | | - button.setTitleColor(.white, for: .normal) |
47 | | - button.layer.borderWidth = 0 |
48 | | - button.titleLabel?.font = .korFont(style: .bold, size: 11) |
49 | | - |
50 | | - } else { |
51 | | - button.setImage(nil, for: .normal) |
52 | | - button.semanticContentAttribute = .unspecified |
53 | | - button.imageEdgeInsets = .zero |
54 | | - button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 12, bottom: 6, right: 12) |
55 | | - button.setBackgroundColor(.white, for: .normal) |
56 | | - button.setTitleColor(.g400, for: .normal) |
57 | | - button.layer.borderWidth = 1 |
58 | | - button.layer.borderColor = UIColor.g200.cgColor |
59 | | - button.titleLabel?.font = .korFont(style: .medium, size: 11) |
60 | | - |
61 | | - } |
62 | | - } |
63 | | - |
64 | | - private var currentAction: UIAction? |
65 | | - |
66 | | - var buttonAction: (() -> Void)? { |
67 | | - didSet { |
68 | | - if let oldAction = currentAction { |
69 | | - button.removeAction(oldAction, for: .touchUpInside) |
70 | | - } |
71 | | - |
72 | | - let action = UIAction { [weak self] _ in |
73 | | - self?.buttonAction?() |
74 | | - } |
75 | | - button.addAction(action, for: .touchUpInside) |
76 | | - currentAction = action |
77 | | - } |
78 | | - } |
| 9 | + |
| 10 | + private enum Constant { |
| 11 | + static let verticalInset: CGFloat = 6 |
| 12 | + static let selectedLeftInset: CGFloat = 10 |
| 13 | + static let normalLeftInset: CGFloat = 12 |
| 14 | + static let rightInset: CGFloat = 12 |
| 15 | + static let checkIconSize: CGSize = .init(width: 16, height: 16) |
| 16 | + static let baselineOffset: CGFloat = -1 |
| 17 | + static let fontSize: CGFloat = 11 |
| 18 | + } |
| 19 | + |
| 20 | + private let button = PPButton( |
| 21 | + style: .secondary, |
| 22 | + text: "", |
| 23 | + font: .korFont(style: .medium, size: Constant.fontSize), |
| 24 | + cornerRadius: 15 |
| 25 | + ).then { |
| 26 | + $0.titleLabel?.lineBreakMode = .byTruncatingTail |
| 27 | + $0.titleLabel?.adjustsFontSizeToFitWidth = false |
| 28 | + } |
| 29 | + |
| 30 | + private var currentAction: UIAction? |
| 31 | + |
| 32 | + override init(frame: CGRect) { |
| 33 | + super.init(frame: frame) |
| 34 | + contentView.addSubview(button) |
| 35 | + setupLayout() |
| 36 | + } |
| 37 | + |
| 38 | + required init?(coder: NSCoder) { |
| 39 | + fatalError("init(coder:) has not been implemented") |
| 40 | + } |
| 41 | + |
| 42 | + private func setupLayout() { |
| 43 | + button.snp.makeConstraints { make in |
| 44 | + make.edges.equalToSuperview() |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + func configure(with title: String, isSelected: Bool) { |
| 49 | + let attributedTitle = NSMutableAttributedString(string: title).then { |
| 50 | + $0.addAttribute( |
| 51 | + .baselineOffset, |
| 52 | + value: Constant.baselineOffset, |
| 53 | + range: NSRange(location: .zero, length: $0.length) |
| 54 | + ) |
| 55 | + } |
| 56 | + |
| 57 | + if isSelected { |
| 58 | + let checkImage = UIImage(named: "icon_check_white")?.withRenderingMode(.alwaysOriginal).resize(to: Constant.checkIconSize) |
| 59 | + |
| 60 | + button.then { |
| 61 | + $0.setImage(checkImage, for: .normal) |
| 62 | + $0.semanticContentAttribute = .forceRightToLeft |
| 63 | + $0.imageEdgeInsets = .init(top: .zero, left: 1, bottom: .zero, right: .zero) |
| 64 | + $0.contentEdgeInsets = .init( |
| 65 | + top: Constant.verticalInset, |
| 66 | + left: Constant.selectedLeftInset, |
| 67 | + bottom: Constant.verticalInset, |
| 68 | + right: Constant.rightInset |
| 69 | + ) |
| 70 | + $0.setBackgroundColor(.blu500, for: .normal) |
| 71 | + $0.setTitleColor(.white, for: .normal) |
| 72 | + $0.layer.borderWidth = .zero |
| 73 | + } |
| 74 | + |
| 75 | + attributedTitle.addAttribute( |
| 76 | + .font, |
| 77 | + value: UIFont.korFont(style: .bold, size: Constant.fontSize)!, |
| 78 | + range: NSRange(location: .zero, length: attributedTitle.length) |
| 79 | + ) |
| 80 | + } else { |
| 81 | + button.then { |
| 82 | + $0.setImage(nil, for: .normal) |
| 83 | + $0.semanticContentAttribute = .unspecified |
| 84 | + $0.imageEdgeInsets = .zero |
| 85 | + $0.contentEdgeInsets = .init( |
| 86 | + top: Constant.verticalInset, |
| 87 | + left: Constant.normalLeftInset, |
| 88 | + bottom: Constant.verticalInset, |
| 89 | + right: Constant.rightInset |
| 90 | + ) |
| 91 | + $0.setBackgroundColor(.white, for: .normal) |
| 92 | + $0.setTitleColor(.g400, for: .normal) |
| 93 | + $0.layer.borderWidth = 1 |
| 94 | + $0.layer.borderColor = UIColor.g200.cgColor |
| 95 | + } |
| 96 | + |
| 97 | + attributedTitle.addAttribute( |
| 98 | + .font, |
| 99 | + value: UIFont.korFont(style: .medium, size: Constant.fontSize)!, |
| 100 | + range: NSRange(location: .zero, length: attributedTitle.length) |
| 101 | + ) |
| 102 | + } |
| 103 | + |
| 104 | + self.button.setAttributedTitle(attributedTitle, for: .normal) |
| 105 | + } |
| 106 | + |
| 107 | + var buttonAction: (() -> Void)? { |
| 108 | + didSet { |
| 109 | + if let oldAction = currentAction { |
| 110 | + self.button.removeAction(oldAction, for: .touchUpInside) |
| 111 | + } |
| 112 | + |
| 113 | + let action = UIAction { [weak self] _ in |
| 114 | + guard let self = self else { return } |
| 115 | + self.buttonAction?() |
| 116 | + } |
| 117 | + |
| 118 | + self.button.addAction(action, for: .touchUpInside) |
| 119 | + self.currentAction = action |
| 120 | + } |
| 121 | + } |
79 | 122 | } |
80 | 123 |
|
81 | 124 | extension UIImage { |
82 | | - func resize(to size: CGSize) -> UIImage? { |
83 | | - UIGraphicsBeginImageContextWithOptions(size, false, 0.0) |
84 | | - defer { UIGraphicsEndImageContext() } |
85 | | - draw(in: CGRect(origin: .zero, size: size)) |
86 | | - return UIGraphicsGetImageFromCurrentImageContext() |
87 | | - } |
| 125 | + func resize(to size: CGSize) -> UIImage? { |
| 126 | + UIGraphicsBeginImageContextWithOptions(size, false, 0.0) |
| 127 | + defer { UIGraphicsEndImageContext() } |
| 128 | + self.draw(in: CGRect(origin: .zero, size: size)) |
| 129 | + return UIGraphicsGetImageFromCurrentImageContext() |
| 130 | + } |
88 | 131 | } |
0 commit comments