jsdw_ios/QuickLocation/Section/Mine/MineView.swift

340 lines
9.6 KiB
Swift

//
// MineView.swift
// QuickLocation
//
// Created based on Lanhu design: ·6
//
import UIKit
import RxSwift
import RxCocoa
final class MineView: UIView {
var disposeBag = DisposeBag()
// MARK: - Design Constants (iOS points, from Lanhu 6 @2x)
private let headerHeight: CGFloat = 160
private let avatarSize: CGFloat = 64
private let editBtnSize: CGFloat = 30
private let copyIconSize: CGFloat = 14
private let vipCardHeight: CGFloat = 90
private let settingsRowHeight: CGFloat = 52
// MARK: - Colors
private let titleColor = UIColor(hexStr: "#1A1A1A")
private let subtitleColor = UIColor(hexStr: "#767676")
private let vipBtnTextColor = UIColor(hexStr: "#00343B")
private func setupRx() {
avatarImageView.rx.tapGesture.subscribe { _ in
AppRouter.push(Route.login)
}.disposed(by: disposeBag)
}
// MARK: - UI Components
private lazy var headerBgImageView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Mine/header_bg")
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
lazy var avatarImageView: UIImageView = {
let iv = UIImageView()
iv.isUserInteractionEnabled = true
iv.contentMode = .scaleAspectFill
iv.layer.cornerRadius = avatarSize / 2
iv.layer.borderWidth = 2
iv.layer.borderColor = UIColor.white.cgColor
iv.clipsToBounds = true
iv.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
iv.layer.shadowOffset = .zero
iv.layer.shadowRadius = 2
iv.layer.shadowOpacity = 1
iv.backgroundColor = UIColor(hexStr: "#E0E0E0")
iv.image = UIImage(named: "Mine/default_avatar")
return iv
}()
lazy var nameLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 16, weight: .heavy)
label.textColor = titleColor
label.text = "肖战大王叫我来巡山"
return label
}()
lazy var editButton: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Mine/edit"), for: .normal)
btn.backgroundColor = .clear
return btn
}()
lazy var idLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 14, weight: .medium)
label.textColor = subtitleColor
label.text = "ID:1234567"
return label
}()
lazy var copyButton: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Mine/copy"), for: .normal)
btn.backgroundColor = .clear
return btn
}()
// VIP Card
private lazy var vipCardView: UIView = {
let view = UIView()
view.layer.cornerRadius = 16
view.clipsToBounds = true
return view
}()
private lazy var vipCardBgImageView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Mine/vip_card")
iv.contentMode = .scaleToFill
return iv
}()
lazy var vipActivateButton: UIButton = {
let btn = UIButton(type: .custom)
btn.backgroundColor = .clear
return btn
}()
// Profile transition background (100pt section below VIP card)
private lazy var profileBgImageView: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "Mine/profile_bg")
iv.contentMode = .scaleToFill
return iv
}()
private lazy var bottomFillView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#F5FBFB")
return view
}()
// Settings Card
private lazy var settingsCardView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 12
view.layer.shadowColor = UIColor(red: 0.898, green: 0.898, blue: 0.898, alpha: 0.3).cgColor
view.layer.shadowOffset = .zero
view.layer.shadowRadius = 4
view.layer.shadowOpacity = 1
return view
}()
lazy var settingsTableView: UITableView = {
let tv = UITableView(frame: .zero, style: .plain)
tv.backgroundColor = .clear
tv.isScrollEnabled = false
tv.separatorStyle = .none
tv.register(MineMenuCell.self)
tv.rowHeight = settingsRowHeight
tv.estimatedRowHeight = settingsRowHeight
return tv
}()
// MARK: - Callbacks
var onMenuTap: ((Int) -> Void)?
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
setupLayout()
setupRx()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Setup
private func setupUI() {
backgroundColor = .white
addSubview(headerBgImageView)
addSubview(avatarImageView)
addSubview(nameLabel)
addSubview(editButton)
addSubview(idLabel)
addSubview(copyButton)
addSubview(vipCardView)
vipCardView.addSubview(vipCardBgImageView)
vipCardView.addSubview(vipActivateButton)
addSubview(profileBgImageView)
addSubview(bottomFillView)
addSubview(settingsCardView)
settingsCardView.addSubview(settingsTableView)
}
private func setupLayout() {
// Header
headerBgImageView.layoutChain
.top().left().right()
.height(headerHeight)
// Avatar
avatarImageView.layoutChain
.top(kStatusBarHeight + 44)
.left(32)
.size(CGSize(width: avatarSize, height: avatarSize))
// Name
nameLabel.layoutChain
.leftToRightOfView(avatarImageView, offset: 20)
.topToView(avatarImageView, offset: 8)
// Edit button
editButton.layoutChain
.right(16)
.centerY(nameLabel)
.size(CGSize(width: editBtnSize, height: editBtnSize))
// ID
idLabel.layoutChain
.leftToRightOfView(avatarImageView, offset: 20)
.topToBottomOfView(nameLabel, offset: 4)
// Copy button
copyButton.layoutChain
.leftToRightOfView(idLabel, offset: 4)
.centerY(idLabel)
.size(CGSize(width: copyIconSize, height: copyIconSize))
// VIP Card
vipCardView.layoutChain
.topToBottomOfView(avatarImageView, offset: 28)
.left(16).right(16)
.height(vipCardHeight)
vipCardBgImageView.layoutChain
.edges()
vipActivateButton.layoutChain
.right(0).centerY()
.width(86).height(28)
// Profile transition background (100pt, overlaps VIP card bottom half)
profileBgImageView.layoutChain
.topToView(vipCardView, offset: 32)
.left().right()
.height(100)
// Fill below profile transition
bottomFillView.layoutChain
.topToBottomOfView(profileBgImageView)
.left().right().bottom()
// Settings Card (fixed height, not stretched)
settingsCardView.layoutChain
.topToBottomOfView(vipCardView, offset: 20)
.left(16).right(16)
.height(312)
settingsTableView.layoutChain
.edges()
}
}
// MARK: - MineMenuCell
final class MineMenuCell: UITableViewCell {
func configure(_ model: MineMenuItem) {
iconImageView.image = UIImage(named: model.icon)
titleLabel.text = model.title
}
private func setupSubviews() {
contentView.addSubview(iconImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(arrowImageView)
contentView.addSubview(dividerLine)
iconImageView.layoutChain
.left(14).centerY()
.size(CGSize(width: 24, height: 24))
titleLabel.layoutChain
.leftToRightOfView(iconImageView, offset: 8)
.centerY()
arrowImageView.layoutChain
.right(14).centerY()
.size(CGSize(width: 18, height: 18))
dividerLine.layoutChain
.left(14).right().bottom()
.height(0.5)
}
var showDivider: Bool = true {
didSet { dividerLine.isHidden = !showDivider }
}
private let iconImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
return iv
}()
private let titleLabel: UILabel = {
let label = UILabel()
label.font = UIFont(name: "PingFangSC-Medium", size: 14)
?? UIFont.systemFont(ofSize: 14, weight: .medium)
label.textColor = UIColor(hexStr: "#1A1A1A")
return label
}()
private let arrowImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
iv.image = UIImage(named: "Mine/arrow_right")
return iv
}()
private let dividerLine: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hexStr: "#EDEDED")
return view
}()
override init(style: CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .clear
selectionStyle = .none
setupSubviews()
}
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
}
}