jsdw_ios/QuickLocation/Section/Schedule/CreateSchedule/CreateSchedulePopView.swift

492 lines
15 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// CreateSchedulePopView.swift
// QuickLocation
//
// Created by on 2026/6/23.
//
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
import BRPickerView
import RxGesture
import CoreLocation
import TagListView
// MARK: - CreateSchedulePopView
class CreateSchedulePopView: UIView {
var disposeBag = DisposeBag()
func setupTagData(_ list: [GroupInfoModel]) {
let nameArr = list.map { $0.name }
tagListView.removeAllTags()
tagListView.addTags(nameArr)
tagListView.tagViews.forEach {
$0.layer.cornerRadius = 4
}
// 使 TagListView intrinsicContentSize
tagListView.setNeedsLayout()
tagListView.layoutIfNeeded()
}
// MARK: - UI
private func setupUI() {
addSubview(lineView)
addSubview(dateView)
addSubview(detailView)
addSubview(scrollView)
lineView.layoutChain
.top(15)
.centerX()
.width(36)
.height(4)
dateView.layoutChain
.topToBottomOfView(lineView, offset: 19)
.edgesHorzontal()
.height(22)
detailView.layoutChain
.topToBottomOfView(dateView, offset: 20)
.edgesHorzontal()
.height(22)
scrollView.layoutChain
.topToBottomOfView(detailView, offset: 15)
.edges(excludingEdge: .top)
}
// MARK: - Views
lazy var lineView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(hexStr: "#EBEBEB")
v.cornerRadius = 2
return v
}()
lazy var dateView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let titleLab = UILabel()
titleLab.text = "行程日期:"
titleLab.font = .systemFont(ofSize: 14, weight: .medium)
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
view.addSubview(titleLab)
titleLab.layoutChain.left(15).centerY()
view.addSubview(dateLab)
dateLab.layoutChain.leftToRightOfView(titleLab).centerY()
return view
}()
lazy var dateLab: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 14, weight: .medium)
label.textColor = UIColor(hexStr: "#16B3FF")
label.isUserInteractionEnabled = true
let fmt = DateFormatter()
fmt.dateFormat = "yyyy年MM月dd日"
label.text = fmt.string(from: Date())
return label
}()
lazy var detailView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let titleLab = UILabel()
titleLab.text = "行程详情"
titleLab.font = .systemFont(ofSize: 14, weight: .medium)
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
view.addSubview(titleLab)
titleLab.layoutChain.left(15).centerY()
view.addSubview(addBtn)
addBtn.layoutChain.right(15).centerY().width(18).height(18)
return view
}()
lazy var addBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Schedule/add"), for: .normal)
btn.backgroundColor = .clear
btn.extendEdgeInsets = UIEdgeInsets(top: 30, left: 30, bottom: 10, right: 15)
return btn
}()
lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = .white
view.showsHorizontalScrollIndicator = false
view.bounces = false
view.delaysContentTouches = false
let contentView = UIView()
contentView.backgroundColor = .clear
view.addSubview(contentView)
contentView.layoutChain
.edges().widthToView(view)
contentView.addSubview(tableView)
tableView.layoutChain
.top()
.edgesHorzontal()
contentView.addSubview(shareGroupView)
shareGroupView.layoutChain
.topToBottomOfView(tableView, offset: 5)
.edgesHorzontal()
contentView.addSubview(createBtn)
createBtn.layoutChain
.topToBottomOfView(shareGroupView, offset: 30)
.edgesHorzontal(30)
.height(50)
.bottom(kSafeBottomMargin + 10)
return view
}()
lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .plain)
tv.backgroundColor = .clear
tv.separatorStyle = .none
tv.estimatedRowHeight = 122
tv.isScrollEnabled = false
tv.showsVerticalScrollIndicator = false
tv.bounces = false
tv.register(SchedulePointCell.self)
return tv
}()
///
lazy var shareGroupView: UIView = {
let view = UIView()
view.backgroundColor = .clear
let titleLab = UILabel()
titleLab.text = "选择分享的圈子"
titleLab.font = .systemFont(ofSize: 14, weight: .medium)
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
view.addSubview(titleLab)
titleLab.layoutChain.left(15).top()
view.addSubview(tagListView)
tagListView.layoutChain
.topToBottomOfView(titleLab, offset: 15)
.edgesHorzontal(15)
.bottom(15)
return view
}()
lazy var tagListView: TagListView = {
let view = TagListView()
view.textFont = UIFont.systemFont(ofSize: 12, weight: .medium)
view.textColor = UIColor(hexStr: "#999999")
view.tagBackgroundColor = UIColor(hexStr: "#F2F2F2")
view.selectedTextColor = UIColor(hexStr: "#16B3FF")
view.tagSelectedBackgroundColor = UIColor(hexStr: "#E3F6FF")
view.selectedBorderColor = UIColor(hexStr: "#16B3FF")
view.paddingX = 15 //
view.paddingY = 10 //
view.alignment = .left //
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var createBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("立即创建", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
btn.cornerRadius = 25
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
// 使 CAShapeLayer mask
layer.cornerRadius = 30
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
layer.masksToBounds = true
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - SchedulePointCell
class SchedulePointCell: UITableViewCell {
var disposeBag = DisposeBag()
var onLocationTap: (() -> Void)?
var onTimeTap: (() -> Void)?
var onRemarkChanged: ((String) -> Void)?
func configure(item: SchedulePointItem, index: Int, total: Int, onDelete: @escaping () -> Void) {
indexLabel.text = "\(index + 1)"
locationLabel.text = item.street.isEmpty ? "点击选择地点" : item.street
remarkTF.text = item.remark
locationLabel.rx.tapGesture
.when(.recognized)
.subscribe(onNext: { [weak self] _ in
self?.onLocationTap?()
})
.disposed(by: disposeBag)
if let expectedTime = item.expectedTime {
timeLabel.text = formatTime(expectedTime)
} else {
timeLabel.text = "请选择到达时间"
}
timeLabel.rx.tapGesture
.when(.recognized)
.subscribe(onNext: { [weak self] _ in
self?.onTimeTap?()
})
.disposed(by: disposeBag)
// 线线
topDashView.isHidden = total <= 1 || index == 0
bottomDashView.isHidden = total <= 1 || index == total - 1
//
deleteBtn.rx.tap
.subscribe(onNext: { onDelete() })
.disposed(by: disposeBag)
}
private func formatTime(_ date: Date) -> String {
let fmt = DateFormatter()
fmt.dateFormat = "HH:mm"
return fmt.string(from: date)
}
// MARK: - Init
@objc private func remarkDidChange() {
onRemarkChanged?(remarkTF.text ?? "")
}
override init(style: CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
setupViews()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func prepareForReuse() {
super.prepareForReuse()
disposeBag = DisposeBag()
}
private func setupViews() {
contentView.addSubview(topDashView)
contentView.addSubview(pointIcon)
contentView.addSubview(bottomDashView)
contentView.addSubview(cardView)
cardView.addSubview(cardCornerView)
cardCornerView.addSubview(indexLabel)
cardCornerView.addSubview(locationLabel)
cardCornerView.addSubview(timeLabel)
cardCornerView.addSubview(remarkTF)
cardCornerView.addSubview(deleteBtn)
topDashView.layoutChain
.top().width(1)
pointIcon.layoutChain
.centerY()
.left(22)
.width(18).height(18)
topDashView.layoutChain
.centerX(pointIcon)
.bottomToTopOfView(pointIcon, offset: -10)
bottomDashView.layoutChain
.topToBottomOfView(pointIcon, offset: 10)
.centerX(pointIcon)
.width(1)
.bottom()
//
cardView.layoutChain
.top(15)
.leftToRightOfView(pointIcon, offset: 20)
.right(15)
// .height(92)
.bottom(15)
cardCornerView.layoutChain.edges()
indexLabel.layoutChain
.top().left()
.width(30).height(20)
locationLabel.layoutChain
.topToBottomOfView(indexLabel, offset: 10)
.left(10)
.compressionHorizontal(.defaultLow)
timeLabel.layoutChain
.topToView(locationLabel)
.right(10)
.compressionHorizontal(.required)
locationLabel.layoutChain.rightToLeftOfView(timeLabel, offset: -8)
deleteBtn.layoutChain
.right(15)
.width(14).height(14)
remarkTF.layoutChain
.topToBottomOfView(locationLabel, offset: 15)
.leftToView(locationLabel)
.rightToLeftOfView(deleteBtn, offset: -10)
.bottom(15)
deleteBtn.layoutChain.centerY(remarkTF)
}
// MARK: - Views
private let topDashView: DashLineView = {
let v = DashLineView()
v.isHidden = true
v.backgroundColor = .clear
return v
}()
private let pointIcon: UIImageView = {
let iv = UIImageView(image: UIImage(named: "Schedule/point"))
iv.contentMode = .scaleAspectFit
return iv
}()
private let bottomDashView: DashLineView = {
let v = DashLineView()
v.isHidden = true
v.backgroundColor = .clear
return v
}()
private let cardView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 0)
view.layer.shadowOpacity = 1
view.layer.shadowRadius = 8
return view
}()
lazy var cardCornerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 10
return view
}()
private let indexLabel: UILabel = {
let l = UILabel()
l.backgroundColor = UIColor(hexStr: "#DCF4FF")
l.textColor = UIColor(hexStr: "#176F9B")
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textAlignment = .center
return l
}()
private let locationLabel: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 14, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
// l.numberOfLines = 0
return l
}()
private let timeLabel: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
l.isUserInteractionEnabled = true
l.textAlignment = .right
return l
}()
lazy var remarkTF: UITextField = {
let tf = UITextField()
tf.font = .systemFont(ofSize: 12)
tf.placeholder = "在此添加备注..."
tf.returnKeyType = .done
return tf
}()
private let deleteBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Schedule/delete"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 15, bottom: 15, right: 15)
return btn
}()
override func layoutSubviews() {
super.layoutSubviews()
cardCornerView.layoutIfNeeded()
indexLabel.setCornerRadius(corners: [.bottomRight], withCornerRadii: CGSize(width: 10, height: 10))
}
}
/// 线线
class DashLineView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
layer.sublayers?.forEach { if $0 is CAShapeLayer { $0.removeFromSuperlayer() } }
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor(hexStr: "#E0E0E0").cgColor
shapeLayer.lineWidth = 1
shapeLayer.lineDashPattern = [4, 4]
shapeLayer.fillColor = nil
let path = UIBezierPath()
path.move(to: CGPoint(x: bounds.midX, y: 0))
path.addLine(to: CGPoint(x: bounds.midX, y: bounds.height))
shapeLayer.path = path.cgPath
layer.addSublayer(shapeLayer)
}
}
/// 线线
class HorizontalDashLineView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
layer.sublayers?.forEach { if $0 is CAShapeLayer { $0.removeFromSuperlayer() } }
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor(hexStr: "#E0E0E0").cgColor
shapeLayer.lineWidth = 1
shapeLayer.lineDashPattern = [4, 4]
shapeLayer.fillColor = nil
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: bounds.midY))
path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.midY))
shapeLayer.path = path.cgPath
layer.addSublayer(shapeLayer)
}
}