jsdw_ios/QuickLocation/Section/Group/MemberInfo/RelationSelectPopVC.swift

242 lines
7.9 KiB
Swift

//
// RelationSelectPopVC.swift
// QuickLocation
//
import UIKit
import Kingfisher
final class RelationSelectPopVC: DLCustomPopVC {
var onConfirm: ((String) -> Void)?
private var selectedIdx: String
private let items: [RelationModel]
private var chipControls: [RelationChipControl] = []
init(currentIdx: String, onConfirm: ((String) -> Void)? = nil) {
self.selectedIdx = currentIdx
self.items = RelationStore.shared.list
self.onConfirm = onConfirm
super.init(nibName: nil, bundle: nil)
popStyle = .bottom
bottomCornerRadius = 40
dimmingClick = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
refreshSelection()
}
private func setupUI() {
let headerBgImage = UIImageView()
headerBgImage.image = UIImage(named: "Common/popup_header_bg")
headerBgImage.contentMode = .scaleToFill
headerBgImage.isUserInteractionEnabled = false
contentView.addSubview(headerBgImage)
headerBgImage.layoutChain
.top()
.edgesHorzontal()
.heightToWidth(120 / 375)
let titleLab = UILabel()
titleLab.text = "关系设置"
titleLab.font = .systemFont(ofSize: 18, weight: .semibold)
titleLab.textColor = UIColor(hexStr: "#293445")
contentView.addSubview(titleLab)
titleLab.layoutChain.top(22).centerX()
let closeBtn = UIButton(type: .custom)
closeBtn.setImage(UIImage(named: "MemberInfo/close_circle"), for: .normal)
closeBtn.imageEdgeInsets = UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
closeBtn.addTarget(self, action: #selector(close), for: .touchUpInside)
contentView.addSubview(closeBtn)
closeBtn.layoutChain.right(6).centerY(titleLab).width(44).height(44)
let columns = 5
let rows = max(1, Int(ceil(Double(max(items.count, 1)) / Double(columns))))
let chipHeight: CGFloat = 32
let rowSpacing: CGFloat = 23
let gridHeight = CGFloat(rows) * chipHeight + CGFloat(max(0, rows - 1)) * rowSpacing
let grid = UIStackView()
grid.axis = .vertical
grid.spacing = rowSpacing
grid.distribution = .fillEqually
grid.clipsToBounds = false
contentView.addSubview(grid)
grid.layoutChain
.topToBottomOfView(titleLab, offset: 22)
.left(16)
.right(16)
.height(gridHeight)
for row in 0..<rows {
let rowStack = UIStackView()
rowStack.axis = .horizontal
rowStack.spacing = 11
rowStack.distribution = .fillEqually
rowStack.alignment = .fill
rowStack.clipsToBounds = false
for col in 0..<columns {
let index = row * columns + col
if items.indices.contains(index) {
let chip = makeChip(items[index], tag: index)
chipControls.append(chip)
rowStack.addArrangedSubview(chip)
} else {
rowStack.addArrangedSubview(UIView())
}
}
grid.addArrangedSubview(rowStack)
}
let confirm = UIButton(type: .custom)
confirm.setTitle("确 定", for: .normal)
confirm.setTitleColor(.white, for: .normal)
confirm.titleLabel?.font = FontManager.boboBold(18)
confirm.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
confirm.layer.cornerRadius = 25
confirm.clipsToBounds = true
confirm.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
contentView.addSubview(confirm)
confirm.layoutChain
.topToBottomOfView(grid, offset: 24)
.left(50)
.right(50)
.height(50)
.bottom(3 + kSafeBottomMargin)
let height = 22 + 22 + 22 + gridHeight + 24 + 50 + 3 + kSafeBottomMargin
contentBgView.layoutChain.height(height)
contentView.layoutChain.height(height)
view.layoutIfNeeded()
}
private func makeChip(_ item: RelationModel, tag: Int) -> RelationChipControl {
let control = RelationChipControl(title: item.name, iconURL: item.icon)
control.tag = tag
control.addTarget(self, action: #selector(tapChip(_:)), for: .touchUpInside)
return control
}
private func refreshSelection() {
for (index, control) in chipControls.enumerated() {
guard items.indices.contains(index) else { continue }
let itemIdx = items[index].idx
control.isSelected = !itemIdx.isEmpty && itemIdx == selectedIdx
}
}
@objc private func tapChip(_ sender: RelationChipControl) {
guard items.indices.contains(sender.tag) else { return }
let idx = items[sender.tag].idx
guard !idx.isEmpty else {
DLToast.show(text: "关系数据异常")
return
}
selectedIdx = idx
refreshSelection()
}
@objc private func confirmTapped() {
guard !selectedIdx.isEmpty else {
DLToast.show(text: "请选择关系")
return
}
let idx = selectedIdx
dismiss(animated: true) { [weak self] in
self?.onConfirm?(idx)
}
}
@objc private func close() {
dismiss(animated: true)
}
}
private final class RelationChipControl: UIControl {
private let titleLabel = UILabel()
private let relationIconView = UIImageView()
private let iconURL: URL?
private var iconRequestVersion = 0
init(title: String, iconURL: String) {
self.iconURL = RelationStore.validIconURL(from: iconURL)
super.init(frame: .zero)
clipsToBounds = false
layer.cornerRadius = 8
layer.borderColor = UIColor(hexStr: "#E8E8E8").cgColor
titleLabel.text = title
titleLabel.font = .systemFont(ofSize: 14, weight: .medium)
titleLabel.textAlignment = .center
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.75
addSubview(titleLabel)
titleLabel.layoutChain.edgesHorzontal(4).centerY()
relationIconView.contentMode = .scaleAspectFit
relationIconView.isUserInteractionEnabled = false
relationIconView.isHidden = true
addSubview(relationIconView)
relationIconView.layoutChain.top(-7).centerX().width(22).height(16)
applyStyle()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var isSelected: Bool {
didSet {
applyStyle()
}
}
override var isHighlighted: Bool {
didSet {
alpha = isHighlighted ? 0.7 : 1
}
}
private func applyStyle() {
backgroundColor = isSelected ? UIColor(hexStr: "#12AEF5") : .white
titleLabel.textColor = isSelected ? .white : UIColor(hexStr: "#293445")
layer.borderWidth = isSelected ? 0 : 1
updateRelationIcon()
}
private func updateRelationIcon() {
relationIconView.kf.cancelDownloadTask()
relationIconView.image = nil
relationIconView.isHidden = true
iconRequestVersion += 1
guard isSelected, let iconURL else { return }
let requestVersion = iconRequestVersion
relationIconView.kf.setImage(with: iconURL) { [weak self] result in
guard let self,
self.isSelected,
self.iconRequestVersion == requestVersion else { return }
switch result {
case .success:
self.relationIconView.isHidden = false
case .failure:
self.relationIconView.image = nil
self.relationIconView.isHidden = true
}
}
}
}