// // 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.. 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 } } } }