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

448 lines
14 KiB
Swift
Raw 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
// MARK: -
struct SchedulePointItem: IdentifiableType, Equatable {
let identity: String = UUID().uuidString
var locationName: String = ""
var address: String = ""
var expectedTime: Date?
var remark: String = ""
}
typealias SchedulePointSection = SectionModel<String, SchedulePointItem>
// MARK: - CreateSchedulePopView
class CreateSchedulePopView: UIView {
var disposeBag = DisposeBag()
let pointsRelay = BehaviorRelay<[SchedulePointItem]>(value: [SchedulePointItem()])
// MARK: - Setup
private func setupRx() {
dateLab.rx.tapGesture.subscribe { _ in
let picker = BRDatePickerView(pickerMode: .YMD)
picker.minDate = Date()
picker.maxDate = Calendar.current.date(byAdding: .day, value: 6, to: Date())
let style = BRPickerStyle()
style.selectRowTextColor = UIColor(hexStr: "#16B3FF")
picker.pickerStyle = style
picker.resultBlock = { [weak self] selectDate, value in
guard let date = selectDate else { return }
let fmt = DateFormatter()
fmt.dateFormat = "yyyy年MM月dd日"
self?.dateLab.text = fmt.string(from: date)
}
picker.show()
}.disposed(by: disposeBag)
//
addBtn.rx.tap
.subscribe(onNext: { [weak self] _ in
guard let self = self else { return }
var list = self.pointsRelay.value
list.append(SchedulePointItem(
locationName: "",
address: "",
expectedTime: nil,
remark: ""
))
self.pointsRelay.accept(list)
})
.disposed(by: disposeBag)
// tableView
pointsRelay
.observe(on: MainScheduler.asyncInstance)
.map { [SchedulePointSection(model: "", items: $0)] }
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
// tableView
pointsRelay
.subscribe(onNext: { [weak self] items in
guard let self = self else { return }
let rowHeight: CGFloat = 122
var h = CGFloat(items.count) * rowHeight
h = max(h, rowHeight)
self.tableView.layoutChain.height(h)
})
.disposed(by: disposeBag)
}
private lazy var dataSource: RxTableViewSectionedReloadDataSource<SchedulePointSection> = {
RxTableViewSectionedReloadDataSource<SchedulePointSection>(
configureCell: { [weak self] _, tv, indexPath, item in
let cell: SchedulePointCell = tv.dequeueReusableCell(for: indexPath)
cell.configure(item: item,
index: indexPath.row,
total: self?.pointsRelay.value.count ?? 0,
onDelete: { [weak self] in
guard let self = self else { return }
var list = self.pointsRelay.value
guard indexPath.row < list.count else { return }
list.remove(at: indexPath.row)
self.pointsRelay.accept(list)
})
return cell
})
}()
// 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: 10, bottom: 10, right: 15)
return btn
}()
lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = .white
view.showsHorizontalScrollIndicator = false
view.bounces = false
let contentView = UIView()
contentView.backgroundColor = .clear
view.addSubview(contentView)
contentView.layoutChain
.edges().widthToView(view)
contentView.addSubview(tableView)
tableView.layoutChain
.top()
.edgesHorzontal()
contentView.addSubview(createBtn)
createBtn.layoutChain
.topToBottomOfView(tableView, 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 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
setupUI()
setupRx()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
layoutIfNeeded()
setCornerRadius(corners: [.topLeft, .topRight], withCornerRadii: CGSize(width: 30, height: 30))
}
}
// MARK: - SchedulePointCell
class SchedulePointCell: UITableViewCell {
var disposeBag = DisposeBag()
func configure(item: SchedulePointItem, index: Int, total: Int, onDelete: @escaping () -> Void) {
disposeBag = DisposeBag()
indexLabel.text = "\(index + 1)"
locationLabel.text = item.locationName.isEmpty ? "点击选择地点" : item.locationName
if let expectedTime = item.expectedTime {
timeLabel.text = formatTime(expectedTime)
}
else {
timeLabel.text = "请选择到达时间"
}
// 线线
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
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") }
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(2)
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(2)
.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)
timeLabel.layoutChain
.centerY(locationLabel)
.leftToRightOfView(locationLabel, offset: 38)
deleteBtn.layoutChain
.bottom(15).right(15)
.width(14).height(14)
remarkTF.layoutChain
.topToBottomOfView(locationLabel, offset: 15)
.leftToView(locationLabel)
.rightToLeftOfView(deleteBtn, offset: -10)
}
// MARK: - Views
private let topDashView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(hexStr: "#E0E0E0")
v.isHidden = true
return v
}()
private let pointIcon: UIImageView = {
let iv = UIImageView(image: UIImage(named: "Schedule/point"))
iv.contentMode = .scaleAspectFit
return iv
}()
private let bottomDashView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(hexStr: "#E0E0E0")
v.isHidden = true
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.lineBreakMode = .byTruncatingTail
return l
}()
private let timeLabel: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
l.isUserInteractionEnabled = true
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))
}
}