// // GroupListPopView.swift // QuickLocation // // Created by 八条 on 2026/5/30. // import UIKit class GroupListPopView: UIView { private static let shared = GroupListPopView(frame: CGRect(origin: .zero, size: kScreenSize)) private var groupList: [GroupInfoModel] = [] /// 完成选中进行回调 private var completion: ((String?) -> Void)? @objc func tap() { completion?(nil) } private var defaultGroupKey: String = "" { didSet { tableView.reloadData() } } private lazy var bgView: UIView = { let view = UIView() view.backgroundColor = .black.withAlphaComponent(0.5) view.clipsToBounds = true return view }() lazy var infoView: UIView = { let view = UIView() view.backgroundColor = .white view.cornerRadius = 20 return view }() lazy var tableView: UITableView = { let tableView = UITableView(frame: .zero, style: .plain) tableView.backgroundColor = .white tableView.separatorStyle = .none tableView.estimatedRowHeight = 68 tableView.showsVerticalScrollIndicator = false tableView.bounces = false tableView.isScrollEnabled = false tableView.register(GroupListPopCell.self) tableView.dataSource = self tableView.delegate = self return tableView }() // MARK: - Init override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .clear addSubview(bgView) bgView.addSubview(tableView) let tap = UITapGestureRecognizer(target: self, action: #selector(tap)) tap.delegate = self addGestureRecognizer(tap) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() tableView.setNeedsLayout() tableView.layoutIfNeeded() tableView.setCornerRadius(corners: [.bottomLeft, .bottomRight], withCornerRadii: CGSize(width: 16, height: 16)) } } // MARK: - Public extension GroupListPopView { /// 显示选择弹窗 /// - Parameters: /// - start: 显示起始点 static func show(start: CGPoint, defaultGroupKey: String, groupList: [GroupInfoModel], completion: @escaping ((String?) -> Void)) { guard let superView = kKeyWindow else { return } if GroupListPopView.shared.superview != nil { GroupListPopView.shared.removeFromSuperview() GroupListPopView.shared.tableView.frame = .zero } GroupListPopView.shared.defaultGroupKey = defaultGroupKey GroupListPopView.shared.bgView.alpha = 1 GroupListPopView.shared.bgView.frame = CGRect(origin: start, size: CGSize(width: kScreenWidth, height: kScreenHeight - start.y)) superView.addSubview(GroupListPopView.shared) superView.bringSubviewToFront(GroupListPopView.shared) let tableViewHeight = CGFloat(GroupListPopView.shared.groupList.count * 30) + 6 GroupListPopView.shared.tableView.frame = CGRect(x: 0, y: -tableViewHeight, width: kScreenWidth, height: tableViewHeight) GroupListPopView.shared.tableView.alpha = 0 GroupListPopView.shared.completion = { (text) in completion(text) GroupListPopView.dismiss() } UIView.animate(withDuration: 0.25) { GroupListPopView.shared.tableView.alpha = 1 GroupListPopView.shared.tableView.frame = CGRect(x: 0, y: 0, width: kScreenWidth, height: tableViewHeight) } } /// 关闭 static func dismiss() { guard GroupListPopView.shared.superview != nil else { return } let tableViewHeight = GroupListPopView.shared.frame.height UIView.animate(withDuration: 0.15) { GroupListPopView.shared.tableView.alpha = 0 GroupListPopView.shared.tableView.frame = CGRect(x: 0, y: -tableViewHeight, width: kScreenWidth, height: tableViewHeight) } UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseIn]) { GroupListPopView.shared.bgView.alpha = 0 } completion: { _ in GroupListPopView.shared.removeFromSuperview() GroupListPopView.shared.tableView.frame = .zero } } } // MARK: - UIGestureRecognizerDelegate extension GroupListPopView: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { if let view = touch.view, !(view == self || view == bgView) { return false } return true } } // MARK: - UITableViewDataSource & UITableViewDelegate extension GroupListPopView: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { groupList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell: GroupListPopCell = tableView.dequeueReusableCell(for: indexPath) cell.configure(model: groupList[indexPath.row], isSelected: defaultGroupKey == groupList[indexPath.row].group_key) return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { completion?(groupList[indexPath.row].group_key) } } // MARK: - GroupListPopCell class GroupListPopCell: UITableViewCell { func configure(model: GroupInfoModel, isSelected: Bool) { avaterImgView.image = model.groupIcon nameLab.text = model.name bgView.isHidden = !isSelected } override init(style: CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none backgroundColor = .clear setupSubviews() } private func setupSubviews() { contentView.addSubview(bgView) contentView.addSubview(avaterImgView) contentView.addSubview(nameLab) bgView.layoutChain.edges() avaterImgView.layoutChain .edgesVertical(14) .left(15) .width(40) .height(40) nameLab.layoutChain .leftToRightOfView(avaterImgView, offset: 11) .right(100, relation: .greaterThanOrEqual) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } lazy var bgView: UIView = { let view = UIView() view.backgroundColor = UIColor(hexStr: "#EFF9FF") let lineView = UIView() lineView.backgroundColor = UIColor(hexStr: "#16B3FF") view.addSubview(lineView) lineView.layoutChain .left() .edgesVertical() .width(6) let selectedIcon = UIImageView() selectedIcon.image = UIImage(named: "Group/selected") view.addSubview(selectedIcon) selectedIcon.layoutChain .right(14) .centerY() .width(24) .height(24) view.isHidden = true return view }() lazy var avaterImgView: UIImageView = { let view = UIImageView() view.backgroundColor = .lightGray view.contentMode = .scaleAspectFill view.cornerRadius = 20 return view }() lazy var nameLab: UILabel = { let label = UILabel() label.textColor = ThemeManager.shared.color.contentColor label.font = .systemFont(ofSize: 15, weight: .medium) return label }() }