Cơ sở sử dụng UICollectionView để tạo giao diện thẻ.
Các phương thức delegate quan trọng cần phân biệt rõ:
protocol NguồnDữLiệuGiaoDiện {
func sốPhần Tử(_ collectionView: UICollectionView) -> Int
func kíchThướcPhầnTử(_ collectionView: UICollectionView, tại indexPath: IndexPath) -> CGSize
}
extension GiaoDiệnThẻ: NguồnDữLiệuGiaoDiện {
func sốPhần Tử(_ collectionView: UICollectionView) -> Int {
return 1
}
func sốLượngPhầnTử(_ collectionView: UICollectionView, trong section: Int) -> Int {
return danhSáchDữLiệu.count
}
func phầnTử(_ collectionView: UICollectionView, tại indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.tạoLại("CellThẻ", forIndexPath: indexPath) as! CellThẻTùyChỉnh
cell.nộiDung.text = danhSáchDữLiệu[indexPath.row]
return cell
}
func phầnBổSung(_ collectionView: UICollectionView, loại kind: String, tại indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let header = collectionView.tạoLạiHeader("TiêuĐề", forIndexPath: indexPath)
return header
} else if kind == UICollectionView.elementKindSectionFooter {
let footer = collectionView.tạoLạiFooter("ChânTrang", forIndexPath: indexPath)
return footer
}
return UICollectionReusableView()
}
}
protocol TươngTácGiaoDiện {
func chọnPhầnTử(_ collectionView: UICollectionView, tại indexPath: IndexPath)
}
extension GiaoDiệnThẻ: TươngTácGiaoDiện {
func chọnPhầnTử(_ collectionView: UICollectionView, tại indexPath: IndexPath) {
let nhóm = indexPath.section
}
}
protocol BốTríDòng {
func kíchThướcPhầnTử(_ collectionView: UICollectionView, tại indexPath: IndexPath) -> CGSize
func khoảngCáchGiữaDòng(_ collectionView: UICollectionView, tại section: Int) -> CGFloat
}
extension GiaoDiệnThẻ: BốTríDòng {
func kíchThướcPhầnTử(_ collectionView: UICollectionView, tại indexPath: IndexPath) -> CGSize {
let chuỗi = danhSáchDữLiệu[indexPath.row]
let kíchThước = chuỗi.kíchThướcVớiChiềuRộng(chiềuRộngMànHình, font: UIFont.systemFont(ofSize: 14))
return CGSize(width: kíchThước.width + 24.0, height: 30)
}
func khoảngCáchGiữaDòng(_ collectionView: UICollectionView, tại section: Int) -> CGFloat {
return 12
}
func khoảngCáchGiữaPhầnTử(_ collectionView: UICollectionView, tại section: Int) -> CGFloat {
return 12
}
}
Để thực hiện căn lề trái cho các phần tử, tham khảo giải pháp sau:
class BốTríDòngCănTrái: UICollectionViewFlowLayout {
enum HướngCăn {
case trái, phải, giữa, tựĐộng
}
var hướngCăn: HướngCăn = .tựĐộng
override func tínhKíchThướcNộiDung() {
super.tínhKíchThướcNộiDung()
if hướngCăn == .trái {
let chiềuRộngTổng = tổngChiềuRộngPhầnTử()
let khoảngCách = (chiềuRộngMànHình - chiềuRộngTổng) / 2
for phầnTử in cácPhầnTử {
phầnTử.vịTrí.x = khoảngCách
phầnTử.vịTrí.y += khoảngCáchGiữaDòng
}
}
}
private func tổngChiềuRộngPhầnTử() -> CGFloat {
var tổng = 0.0
for phầnTử in cácPhầnTử {
tổng += phầnTử.kíchThước.width
}
return tổng
}
}
Mẫu phần tử hiển thị thẻ:
class CellThẻTùyChỉnh: UICollectionViewCell {
let nộiDung = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
thiếtLậpGiaoDiện()
}
private func thiếtLậpGiaoDiện() {
backgroundColor = UIColor(red: 0.96, green: 0.97, blue: 0.98, alpha: 1.0)
layer.cornerRadius = 4
layer.masksToBounds = true
addSubview(nộiDung)
nộiDung.textColor = UIColor.darkText
nộiDung.font = UIFont.systemFont(ofSize: 13)
nộiDung.textAlignment = .center
nộiDung.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(12)
}
}
}
Kết hợp UICollectionView với giao diện tùy chỉnh:
class GiaoDiệnThẻ: UIView {
lazy var collectionView: UICollectionView = {
let bốTrí = BốTríDòngCănTrái()
bốTrí.hướngCăn = .trái
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: bốTrí)
collectionView.backgroundColor = .white
collectionView.register(CellThẻTùyChỉnh.self, forCellWithReuseIdentifier: "CellThẻ")
collectionView.delegate = self
collectionView.dataSource = self
return collectionView
}()
func cậpNhậtDữLiệu() {
danhSáchDữLiệu = ["Thẻ 1", "Thẻ 2", "Thẻ dài dài dài", "Thẻ 4", "Thẻ 5"]
collectionView.reloadData()
}
}