jsdw_ios/QuickLocation/Section/Group/GroupMemberList/GroupMemberListView.swift

1124 lines
35 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.

//
// GroupMemberListView.swift
// QuickLocation
//
// Created by on 2026/6/29.
//
import UIKit
import RxSwift
import RxCocoa
class GroupMemberListView: UIView {
var disposeBag = DisposeBag()
func updateArrowVisibility() {
let offsetX = collectionView.contentOffset.x
let contentW = collectionView.contentSize.width
let viewW = collectionView.bounds.width
memberArrowLeft.isHidden = offsetX <= 0
memberArrowRight.isHidden = offsetX >= contentW - viewW
}
private func setupRx() {
backBtn.rx.tap.subscribe(onNext: { _ in
AppRouter.shared.popOrDismiss()
}).disposed(by: disposeBag)
collectionView.rx.contentOffset
.subscribe(onNext: { [weak self] _ in
self?.updateArrowVisibility()
})
.disposed(by: disposeBag)
//
selectedDate.subscribe(onNext: { [weak self] date in
guard let self = self else { return }
let fmt = DateFormatter()
fmt.dateFormat = "MM月"
self.monthLab.text = fmt.string(from: date)
}).disposed(by: disposeBag)
// / 7
datePreviousBtn.rx.tap.subscribe(onNext: { [weak self] _ in
guard let self = self else { return }
let target = self.dateCollectionView.contentOffset.x - self.dateItemWidth * CGFloat(self.daysPerPage)
self.dateCollectionView.setContentOffset(CGPoint(x: max(0, target), y: 0), animated: true)
}).disposed(by: disposeBag)
dateNextBtn.rx.tap.subscribe(onNext: { [weak self] _ in
guard let self = self else { return }
var target = self.dateCollectionView.contentOffset.x + self.dateItemWidth * CGFloat(self.daysPerPage)
let maxOffset = CGFloat(self.dateItems.count) * self.dateItemWidth - self.dateCollectionView.bounds.width
target = min(max(0, maxOffset), target)
self.dateCollectionView.setContentOffset(CGPoint(x: target, y: 0), animated: true)
}).disposed(by: disposeBag)
}
private func setupUI() {
addSubview(navBgView)
addSubview(navBarView)
navBarView.addSubview(navTitleLabel)
navBarView.addSubview(backBtn)
addSubview(memberArrowLeft)
addSubview(collectionView)
addSubview(memberArrowRight)
addSubview(reportView)
navBgView.layoutChain
.edges(excludingEdge: .bottom)
.heightToWidth(160/375)
navBarView.layoutChain
.edges(excludingEdge: .bottom)
.height(kNaviHeight)
navTitleLabel.layoutChain
.top(kStatusBarHeight + 12)
.centerY(backBtn)
.centerX()
backBtn.layoutChain
.centerY(navTitleLabel)
.left(15)
.width(24)
.height(24)
collectionView.layoutChain
.topToBottomOfView(navBarView, offset: 0)
.height(90)
.edgesHorzontal(28)
memberArrowLeft.layoutChain
.rightToLeftOfView(collectionView, offset: -8)
.height(14)
.width(5)
.centerY(collectionView)
memberArrowRight.layoutChain
.leftToRightOfView(collectionView, offset: 8)
.height(14)
.width(5)
.centerY(collectionView)
reportView.layoutChain
.topToBottomOfView(collectionView, offset: 10)
.edges(excludingEdge: .top)
}
lazy var navBgView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Common/navBar_bg_2")
iv.contentMode = .scaleAspectFill
return iv
}()
lazy var navBarView: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
lazy var navTitleLabel: UILabel = {
let label = UILabel()
label.text = "圈子成员"
label.font = .systemFont(ofSize: 18, weight: .medium)
label.textColor = ThemeManager.shared.color.titleAuxColor
label.textAlignment = .center
return label
}()
lazy var backBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Common/back"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 54, left: 15, bottom: 100, right: 100)
return btn
}()
// MARK: -
lazy var memberArrowLeft: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "GroupMemberList/member_left")
view.isHidden = true
return view
}()
lazy var memberArrowRight: UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "GroupMemberList/member_right")
view.isHidden = true
return view
}()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cvWidth = kScreenWidth - 56
layout.itemSize = CGSize(width: 65, height: 90)
layout.minimumLineSpacing = 4
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .clear
cv.showsHorizontalScrollIndicator = false
cv.register(GroupMemberListCell.self)
return cv
}()
// MARK: -
lazy var unlockVipMaskView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.isHidden = true
let maskBg = UIImageView(image: UIImage(named: "GroupMemberList/mask_bg"))
view.addSubview(maskBg)
maskBg.layoutChain.edges()
let tipsImg = UIImageView(image: UIImage(named: "GroupMemberList/mask_tips"))
view.addSubview(tipsImg)
tipsImg.layoutChain
.top(83)
.centerX()
.width(283)
.height(194)
let btn = UIButton()
btn.setTitle("立即开通", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
btn.setBackgroundColor(UIColor(hexStr: "#FF7B24"), for: .normal)
btn.cornerRadius = 25
btn.rx.tap.subscribe(onNext: { _ in
AppRouter.push(Route.vipRecharge)
}).disposed(by: disposeBag)
view.addSubview(btn)
btn.layoutChain
.topToBottomOfView(tipsImg, offset: 23)
.centerX()
.width(224)
.height(50)
return view
}()
// MARK: -
lazy var reportView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#F5FBFF")
view.layer.cornerRadius = 20
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
let monthView = UIView()
monthView.backgroundColor = UIColor(hexStr: "#57C7FF")
monthView.cornerRadius = 6
monthView.addSubview(monthLab)
monthLab.layoutChain
.edgesVertical(2)
.edgesHorzontal(12)
view.addSubview(monthView)
monthView.layoutChain
.top(15)
.left(15)
let totalLab = UILabel()
totalLab.text = "本周总计里程"
totalLab.font = .systemFont(ofSize: 10, weight: .medium)
totalLab.textColor = UIColor(hexStr: "#333333")
view.addSubview(totalLab)
totalLab.layoutChain
.leftToRightOfView(monthView, offset: 21)
.centerY(monthView)
view.addSubview(mileageLab)
mileageLab.layoutChain
.leftToRightOfView(totalLab, offset: 5)
.centerY(monthView)
let highLab = UILabel()
highLab.text = "本周最高时速"
highLab.font = .systemFont(ofSize: 10, weight: .medium)
highLab.textColor = UIColor(hexStr: "#333333")
view.addSubview(highLab)
highLab.layoutChain
.leftToRightOfView(mileageLab, offset: 23)
.centerY(monthView)
view.addSubview(speedLab)
speedLab.layoutChain
.leftToRightOfView(highLab, offset: 5)
.centerY(monthView)
view.addSubview(dateView)
dateView.layoutChain
.topToBottomOfView(monthView, offset: 10)
.edgesHorzontal()
view.addSubview(scrollView)
scrollView.layoutChain
.topToBottomOfView(dateView)
.edges(excludingEdge: .top)
view.addSubview(unlockVipMaskView)
unlockVipMaskView.layoutChain
.topToBottomOfView(dateView)
.edges(excludingEdge: .top)
return view
}()
lazy var monthLab: UILabel = {
let label = UILabel()
label.text = " "
label.font = .systemFont(ofSize: 14, weight: .medium)
label.textColor = UIColor(hexStr: "#0F2846")
label.textAlignment = .center
return label
}()
///
lazy var mileageLab: UILabel = {
let label = UILabel()
label.text = "0km"
label.font = .systemFont(ofSize: 16, weight: .medium)
label.textColor = UIColor(hexStr: "#16B3FF")
return label
}()
///
lazy var speedLab: UILabel = {
let label = UILabel()
label.text = "0km/h"
label.font = .systemFont(ofSize: 16, weight: .medium)
label.textColor = UIColor(hexStr: "#16B3FF")
return label
}()
// MARK: -
private var dateItems: [DateItem] = []
let selectedDate = BehaviorRelay<Date>(value: Date())
private let daysPerPage = 7
///
var selectedMemberIsSelf = true {
didSet { updateDateSelectability() }
}
struct DateItem {
let date: Date
let day: Int
let isToday: Bool
let isFuture: Bool
let isSelectable: Bool
}
/// VIP
private var maxSelectableDays: Int {
switch AppContextManager.shared.vip {
case 1: return 0 //
case 2: return selectedMemberIsSelf ? 7 : 1
case 3: return selectedMemberIsSelf ? 30 : 14
default: return 0
}
}
/// dateItems isSelectable
private func updateDateSelectability() {
let calendar = Calendar.current
let today = Date()
let maxDays = maxSelectableDays
dateItems = dateItems.map { item in
let daysAgo = calendar.dateComponents([.day], from: item.date, to: today).day ?? 0
return DateItem(date: item.date, day: item.day, isToday: item.isToday,
isFuture: item.isFuture,
isSelectable: maxDays > 0 && !item.isFuture && daysAgo <= maxDays - 1)
}
dateCollectionView.reloadData()
}
private func generateDateItems() {
let calendar = Calendar.current
let today = Date()
// 31 3 = 35 5 × 7
let pastDays = 31
let futureDays = 3
let totalDays = pastDays + 1 + futureDays // 35
dateItems = (0..<totalDays).map { i in
let offset = i - pastDays
let date = calendar.date(byAdding: .day, value: offset, to: today) ?? today
let day = calendar.component(.day, from: date)
let isFuture = date > today
let daysAgo = calendar.dateComponents([.day], from: date, to: today).day ?? 0
return DateItem(date: date, day: day,
isToday: calendar.isDateInToday(date),
isFuture: isFuture,
isSelectable: maxSelectableDays > 0 && !isFuture && daysAgo <= maxSelectableDays - 1)
}
}
///
lazy var dateView: UIView = {
let view = UIView()
view.backgroundColor = .clear
generateDateItems()
view.addSubview(datePreviousBtn)
view.addSubview(dateNextBtn)
view.addSubview(dateCollectionView)
datePreviousBtn.layoutChain
.left(15)
.edgesVertical(10)
.width(20)
.height(20)
dateNextBtn.layoutChain
.right(15)
.centerY()
.width(20)
.height(20)
dateCollectionView.layoutChain
.leftToRightOfView(datePreviousBtn, offset: 5)
.rightToLeftOfView(dateNextBtn, offset: -5)
.edgesVertical()
DispatchQueue.main.async { self.scrollToToday() }
return view
}()
private var dateItemWidth: CGFloat {
let available = kScreenWidth - 15 - 20 - 5 - 5 - 20 - 15
return floor(available / CGFloat(daysPerPage))
}
lazy var dateCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: dateItemWidth, height: 40)
layout.minimumLineSpacing = 0
layout.scrollDirection = .horizontal
layout.sectionInset = .zero
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .clear
cv.showsHorizontalScrollIndicator = false
cv.isPagingEnabled = true
cv.register(DateCell.self)
cv.dataSource = self
cv.delegate = self
return cv
}()
lazy var datePreviousBtn: UIButton = {
let btn = UIButton()
btn.setImage(UIImage(named: "GroupMemberList/date_left"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 0)
return btn
}()
lazy var dateNextBtn: UIButton = {
let btn = UIButton()
btn.setImage(UIImage(named: "GroupMemberList/date_right"), for: .normal)
btn.extendEdgeInsets = UIEdgeInsets(top: 15, left: 0, bottom: 15, right: 15)
return btn
}()
// MARK: -
lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = .clear
view.showsVerticalScrollIndicator = false
view.bounces = false
view.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSafeBottomMargin, right: 0)
let contentView = UIView()
contentView.backgroundColor = .clear
view.addSubview(contentView)
contentView.layoutChain.edges().widthToView(view)
contentView.addSubview(drivingAnalysisView)
drivingAnalysisView.layoutChain
.top(5)
.edgesHorzontal(15)
.height(249)
contentView.addSubview(recordView)
recordView.layoutChain
.topToBottomOfView(drivingAnalysisView, offset: 15)
.edgesHorzontal(15)
.bottom(20)
return view
}()
lazy var drivingAnalysisView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 10
let titleBg = UIImageView(image: UIImage(named: "GroupMemberList/title_bg"))
view.addSubview(titleBg)
let titleLab = UILabel()
titleLab.text = "驾驶分析"
titleLab.font = .systemFont(ofSize: 16, weight: .medium)
view.addSubview(titleLab)
titleLab.layoutChain
.top(15)
.centerX()
titleBg.layoutChain
.centerX()
.bottomToView(titleLab, offset: 5)
view.addSubview(drivingEventCV)
drivingEventCV.layoutChain
.topToBottomOfView(titleBg, offset: 20)
.edgesHorzontal()
.bottom(20)
return view
}()
lazy var drivingEventCV: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 66, height: 75)
layout.minimumLineSpacing = 15
layout.scrollDirection = .vertical
layout.sectionInset = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .clear
cv.showsHorizontalScrollIndicator = false
cv.isScrollEnabled = false
cv.register(DrivingEventCell.self)
return cv
}()
// MARK: -
lazy var recordView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 10
let titleBg = UIImageView(image: UIImage(named: "GroupMemberList/title_bg"))
view.addSubview(titleBg)
let titleLab = UILabel()
titleLab.text = "行程记录"
titleLab.font = .systemFont(ofSize: 16, weight: .medium)
view.addSubview(titleLab)
titleLab.layoutChain
.top(15)
.centerX()
titleBg.layoutChain
.centerX()
.bottomToView(titleLab, offset: 5)
view.addSubview(tableView)
tableView.layoutChain
.topToBottomOfView(titleBg, offset: 10)
.edgesHorzontal()
.bottom()
view.addSubview(nodataLab)
nodataLab.layoutChain.centerX().centerY()
return view
}()
lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.estimatedRowHeight = 177
tableView.showsVerticalScrollIndicator = false
tableView.isScrollEnabled = false
tableView.register(ScheduleRecordCell.self)
return tableView
}()
lazy var nodataLab: UILabel = {
let l = UILabel()
l.text = "暂无行程记录"
l.font = .systemFont(ofSize: 12, weight: .regular)
l.textColor = UIColor(hexStr: "#999999")
return l
}()
///
func scrollReportToTop() {
scrollView.setContentOffset(.zero, animated: false)
}
/// 5 items 28-34 3
func scrollToToday() {
let page: CGFloat = 4
let offset = page * CGFloat(daysPerPage) * dateItemWidth
dateCollectionView.contentOffset.x = offset
}
func updateTableViewHeight(count: Int) {
let h = CGFloat(count) * 179
tableView.layoutChain.height(h > 0 ? h : 179)
nodataLab.isHidden = h > 0
}
override func layoutSubviews() {
super.layoutSubviews()
updateArrowVisibility()
}
override init(frame: CGRect) {
super.init(frame: .zero)
backgroundColor = .white
setupUI()
setupRx()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - UICollectionViewDataSource & Delegate ()
extension GroupMemberListView: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
dateItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: DateCell = collectionView.dequeueReusableCell(for: indexPath)
let item = dateItems[indexPath.row]
let isSel = Calendar.current.isDate(item.date, inSameDayAs: selectedDate.value)
cell.configure(item: item, isSelected: isSel)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard collectionView == dateCollectionView else { return }
let item = dateItems[indexPath.row]
guard item.isSelectable else { return }
let oldDate = selectedDate.value
selectedDate.accept(item.date)
if let oldRow = dateItems.firstIndex(where: { Calendar.current.isDate($0.date, inSameDayAs: oldDate) }),
let oldCell = dateCollectionView.cellForItem(at: IndexPath(row: oldRow, section: 0)) as? DateCell {
oldCell.configure(item: dateItems[oldRow], isSelected: false)
}
if let newCell = dateCollectionView.cellForItem(at: indexPath) as? DateCell {
newCell.configure(item: item, isSelected: true)
}
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
guard scrollView == dateCollectionView else { return }
let targetX = targetContentOffset.pointee.x
let idx = round(targetX / dateItemWidth)
targetContentOffset.pointee.x = idx * dateItemWidth
}
}
// MARK: - DateCell
class DateCell: UICollectionViewCell {
private let bgView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(hexStr: "#16B3FF")
v.cornerRadius = 11
v.isHidden = true
return v
}()
private let dayLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 14, weight: .medium)
l.textAlignment = .center
return l
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(bgView)
contentView.addSubview(dayLab)
bgView.layoutChain.centerX().centerY().width(36).height(22)
dayLab.layoutChain.centerX().centerY()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func configure(item: GroupMemberListView.DateItem, isSelected: Bool) {
dayLab.text = "\(item.day)"
let disabled = item.isFuture || !item.isSelectable
bgView.isHidden = !isSelected || disabled
dayLab.textColor = disabled ? UIColor(hexStr: "#D1D1D6")
: isSelected ? .white
: UIColor(hexStr: "#333333")
}
}
// MARK: - GroupMemberListCell
class GroupMemberListCell: UICollectionViewCell {
func configure(model: GroupMemberModel, isCurrentUser: Bool, isSelected: Bool) {
avaterImgView.image = model.userIcon
vipIcon.image = model.vipIcon
nameLab.text = model.nick_name
nameLab.textColor = UIColor(hexStr: isCurrentUser ? "#16B3FF" : "#0F2846")
selectedBgView.isHidden = !isSelected
//
if AppContextManager.shared.vip > 1, model.is_online {
batteryInfoView.isHidden = model.battery.int == 0
// 16
let batteryPercent = min(CGFloat(model.battery.int), 100)
batteryView.layoutChain.width(CGFloat(16 - 1) * batteryPercent / 100.0)
batteryLab.text = "\(model.battery)%"
}
}
private func setupSubviews() {
contentView.addSubview(selectedBgView)
contentView.addSubview(avaterImgView)
contentView.addSubview(vipIcon)
contentView.addSubview(batteryInfoView)
batteryInfoView.addSubview(cornerView)
cornerView.addSubview(batteryView)
cornerView.addSubview(batteryIcon)
cornerView.addSubview(batteryLab)
contentView.addSubview(nameLab)
setupLayout()
}
private func setupLayout() {
selectedBgView.layoutChain.edges()
avaterImgView.layoutChain
.top(11)
.edgesHorzontal(10)
.heightToWidth(1)
batteryInfoView.layoutChain
.leftToView(avaterImgView)
.rightToView(avaterImgView)
.bottomToView(avaterImgView)
.height(12)
cornerView.layoutChain.edges()
batteryIcon.layoutChain
.left(7)
.centerY()
.width(16)
.height(8)
batteryView.layoutChain
.topToView(batteryIcon)
.leftToView(batteryIcon, offset: -1)
.bottomToView(batteryIcon)
batteryLab.layoutChain
.leftToRightOfView(batteryIcon, offset: 4)
.right(5)
.centerY()
vipIcon.layoutChain
.topToView(avaterImgView, offset: -8)
.leftToView(avaterImgView, offset: -6)
.width(25)
.height(21)
nameLab.layoutChain
.topToBottomOfView(batteryInfoView, offset: 4)
.edgesHorzontal()
}
lazy var selectedBgView: UIImageView = {
let view = UIImageView(image: UIImage(named: "GroupMemberList/selected_bg"))
view.contentMode = .scaleAspectFill
view.isHidden = true
return view
}()
lazy var avaterImgView: UIImageView = {
let view = UIImageView()
view.backgroundColor = .lightGray
view.contentMode = .scaleAspectFill
view.cornerRadius = 25
return view
}()
lazy var batteryInfoView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.1).cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 2)
view.layer.shadowOpacity = 1
view.layer.shadowRadius = 6
view.isHidden = true
return view
}()
lazy var cornerView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.cornerRadius = 6
return view
}()
lazy var batteryView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#75E582")
return view
}()
lazy var batteryIcon: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
view.image = UIImage(named: "Home/battery")
return view
}()
lazy var batteryLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#D4D4D4")
label.font = .systemFont(ofSize: 6, weight: .medium)
return label
}()
lazy var vipIcon: UIImageView = {
let view = UIImageView()
return view
}()
lazy var nameLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#0F2846")
label.font = .systemFont(ofSize: 12, weight: .medium)
label.textAlignment = .center
return label
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override init(frame: CGRect) {
super.init(frame: frame)
setupSubviews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - DrivingEventCell
class DrivingEventCell: UICollectionViewCell {
func configure(_ item: DrivingEventItem) {
iconView.image = UIImage(named: item.iconName)
nameLab.text = "\(item.title)\n\(item.count)"
}
private let bgView: UIView = {
let v = UIView()
v.backgroundColor = UIColor(hexStr: "#F5FBFF")
v.cornerRadius = 8
return v
}()
lazy var iconView: UIImageView = {
let view = UIImageView()
view.contentMode = .scaleAspectFill
return view
}()
lazy var nameLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .regular)
l.textAlignment = .center
l.numberOfLines = 0
return l
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(bgView)
contentView.addSubview(iconView)
contentView.addSubview(nameLab)
bgView.layoutChain
.edges(excludingEdge: .top)
.height(60)
iconView.layoutChain
.top()
.centerX()
.width(32)
.heightToWidth(1)
nameLab.layoutChain
.topToBottomOfView(iconView, offset: 8)
.edgesHorzontal()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
// MARK: - ScheduleRecordCells
class ScheduleRecordCell: UITableViewCell {
func configure(_ model: ScheduleRecordModel) {
distanceLab.text = String(format: "%.1fkm", model.distance_km)
speedLab.text = String(format: "最高时速 %.0fkm/h", model.max_speed)
scoreLab.text = model.score.string
dayLab.text = model.start_time.isoStringToCustom(model.start_time, format: "dd") ?? ""
yearMonthLab.text = model.start_time.isoStringToCustom(model.start_time, format: "yyyy.MM") ?? ""
let startTime = model.start_time.isoStringToCustom(model.start_time, format: "HH:mm") ?? ""
let endTime = model.end_time.isoStringToCustom(model.end_time, format: "HH:mm") ?? ""
durationLab.text = "\(startTime)-\(endTime)(\(model.duration_minutes)分钟)"
guard let start_address = model.start_address,
let end_address = model.end_address else { return }
startLab.text = start_address.street
endLab.text = end_address.street
}
private func setupViews() {
contentView.addSubview(dotView)
contentView.addSubview(dayLab)
contentView.addSubview(yearMonthLab)
contentView.addSubview(distanceLab)
contentView.addSubview(durationLab)
contentView.addSubview(detailView)
detailView.addSubview(headerBgView)
detailView.addSubview(speedLab)
detailView.addSubview(scroreTitleLab)
detailView.addSubview(scoreLab)
detailView.addSubview(unitLab)
detailView.addSubview(startTitleLab)
detailView.addSubview(startLab)
detailView.addSubview(endTitleLab)
detailView.addSubview(endLab)
contentView.addSubview(lineView)
dotView.layoutChain
.left(15)
.width(8)
.heightToWidth(1)
dayLab.layoutChain
.top(15)
.leftToRightOfView(dotView, offset: 8)
dotView.layoutChain.centerY(dayLab)
yearMonthLab.layoutChain
.leftToRightOfView(dayLab, offset: 4)
.bottomToView(dayLab, offset: -2)
distanceLab.layoutChain
.leftToRightOfView(yearMonthLab, offset: 8)
.bottomToView(yearMonthLab)
durationLab.layoutChain
.centerY(distanceLab)
.leftToRightOfView(distanceLab, offset: 6)
detailView.layoutChain
.topToBottomOfView(dayLab, offset: 15)
.left(28)
.right(15)
.height(110)
.bottom(15)
headerBgView.layoutChain
.edges(excludingEdge: .bottom)
.height(38)
speedLab.layoutChain
.top(11)
.left(15)
unitLab.layoutChain
.right(10)
.centerY(speedLab)
scoreLab.layoutChain
.rightToLeftOfView(unitLab)
.centerY(speedLab)
scroreTitleLab.layoutChain
.rightToLeftOfView(scoreLab, offset: -3)
.centerY(speedLab)
startTitleLab.layoutChain
.topToBottomOfView(headerBgView, offset: 12)
.left(15)
startLab.layoutChain
.leftToRightOfView(startTitleLab, offset: 2)
.centerY(startTitleLab)
endTitleLab.layoutChain
.topToBottomOfView(startTitleLab, offset: 11)
.leftToView(startTitleLab)
endLab.layoutChain
.leftToRightOfView(endTitleLab, offset: 2)
.centerY(endTitleLab)
lineView.layoutChain
.height(0.5)
.edgesHorzontal(15)
.bottom()
}
lazy var dotView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#16B3FF")
view.cornerRadius = 4
return view
}()
lazy var dayLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 20, weight: .bold)
l.textColor = UIColor(hexStr: "#16B3FF")
return l
}()
lazy var yearMonthLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .bold)
l.textColor = UIColor(hexStr: "#66CDFF")
return l
}()
lazy var distanceLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
return l
}()
lazy var durationLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .regular)
l.textColor = UIColor(hexStr: "#333333")
return l
}()
lazy var detailView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#F5FBFF")
view.cornerRadius = 10
view.clipsToBounds = true
return view
}()
lazy var headerBgView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#C4E8FF")
return view
}()
lazy var speedLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
return l
}()
lazy var scroreTitleLab: UILabel = {
let l = UILabel()
l.text = "安全评分"
l.font = .systemFont(ofSize: 10, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
return l
}()
lazy var scoreLab: UILabel = {
let l = UILabel()
l.text = "0"
l.font = .systemFont(ofSize: 24, weight: .medium)
l.textColor = UIColor(hexStr: "#16B3FF")
return l
}()
lazy var unitLab: UILabel = {
let l = UILabel()
l.text = ""
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#16B3FF")
return l
}()
lazy var startTitleLab: UILabel = {
let l = UILabel()
l.text = "起点:"
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#666666")
return l
}()
lazy var startLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
return l
}()
lazy var endTitleLab: UILabel = {
let l = UILabel()
l.text = "终点:"
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#666666")
return l
}()
lazy var endLab: UILabel = {
let l = UILabel()
l.font = .systemFont(ofSize: 12, weight: .medium)
l.textColor = UIColor(hexStr: "#333333")
return l
}()
lazy var lineView: UIView = {
let view = UIView()
view.backgroundColor = ThemeManager.shared.color.lineColor
return view
}()
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 awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}