jsdw_ios/QuickLocation/Section/PopupWindow/PromotionalActivitiesView.s...

657 lines
20 KiB
Swift

//
// PromotionalActivitiesView.swift
// QuickLocation
//
// Created by on 2026/7/3.
//
import UIKit
import RxSwift
import RxCocoa
enum PromotionalActivitiesItem {
case recommend(model: VipExpenseModel)
case normal(model: VipExpenseModel)
}
class PromotionalActivitiesView: UIView {
var disposeBag = DisposeBag()
private func setupRx() {
backBtn.rx.tap.subscribe(onNext: { _ in
VipWaivePopView.show()
}).disposed(by: disposeBag)
}
private func setupUI() {
addSubview(scrollView)
addSubview(navBarView)
navBarView.addSubview(navTitleLabel)
addSubview(backBtn)
navBarView.layoutChain
.edges(excludingEdge: .bottom)
.height(kNaviHeight)
navTitleLabel.layoutChain
.top(kStatusBarHeight + 12)
.centerY(backBtn)
.centerX()
backBtn.layoutChain
.top(kStatusBarHeight + 12)
.left(15)
.width(24)
.height(24)
addSubview(bottomView)
bottomView.layoutChain
.edges(excludingEdge: .top)
.height(120)
scrollView.layoutChain
.edges(excludingEdge: .bottom)
.bottomToTopOfView(bottomView)
}
lazy var navBarView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.alpha = 0
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: 15, right: 100)
return btn
}()
lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = UIColor(hexStr: "#F6F9FB")
view.showsVerticalScrollIndicator = false
view.delegate = self
view.bounces = false
view.contentInsetAdjustmentBehavior = .never
view.addSubview(scrollContentView)
scrollContentView.layoutChain
.edges().widthToView(view)
let headerBgImgView = UIImageView(image: UIImage(named: "PromotionalActivities/header_bg"))
headerBgImgView.contentMode = .scaleAspectFill
scrollContentView.addSubview(headerBgImgView)
headerBgImgView.layoutChain
.edges(excludingEdge: .bottom)
.heightToWidth(285/375)
let infoView = UIView()
infoView.backgroundColor = UIColor(hexStr: "#F6F9FB")
infoView.layer.cornerRadius = 30
scrollContentView.addSubview(infoView)
infoView.layoutChain
.topToBottomOfView(headerBgImgView, offset: -65)
.edges(excludingEdge: .top)
let iconView = UIImageView(image: UIImage(named: "PromotionalActivities/vip_icon"))
infoView.addSubview(iconView)
iconView.layoutChain
.top(20)
.left(15)
.width(20)
.heightToWidth(1)
let titleLab = UILabel()
titleLab.text = "即刻加入会员"
titleLab.font = .systemFont(ofSize: 16, weight: .semibold)
titleLab.textColor = UIColor(hexStr: "#333333")
infoView.addSubview(titleLab)
titleLab.layoutChain
.leftToRightOfView(iconView, offset: 4)
.centerY(iconView)
scrollContentView.addSubview(tableView)
tableView.layoutChain
.topToBottomOfView(titleLab, offset: 0)
.edgesHorzontal()
let agreementView = UIView()
infoView.addSubview(agreementView)
agreementView.layoutChain
.topToBottomOfView(tableView, offset: 15)
.left(15)
.right(15)
.height(16)
agreementView.addSubview(agreementCheckBtn)
agreementCheckBtn.layoutChain
.left(0)
.centerY()
.width(16)
.height(16)
agreementView.addSubview(agreementTextView)
agreementTextView.layoutChain
.leftToRightOfView(agreementCheckBtn, offset: 3)
.right(0)
.centerY()
.bottom(0)
let benefitsImgView = UIImageView(image: UIImage(named: "PromotionalActivities/benefits"))
benefitsImgView.contentMode = .scaleAspectFill
infoView.addSubview(benefitsImgView)
benefitsImgView.layoutChain
.topToBottomOfView(agreementView, offset: 20)
.edgesHorzontal(15)
.bottom(15, relation: .greaterThanOrEqual)
.heightToWidth(148/375)
return view
}()
lazy var scrollContentView: UIView = {
let view = UIView()
view.backgroundColor = .clear
return view
}()
lazy var tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .plain)
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.estimatedRowHeight = 106
tableView.isScrollEnabled = false
tableView.showsVerticalScrollIndicator = false
tableView.register(PromotionalNormalCell.self)
tableView.register(PromotionalRecommendCell.self)
return tableView
}()
lazy var bottomView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.addSubview(countdownContainer)
countdownContainer.layoutChain
.top(11)
.centerX()
view.addSubview(confirmBtn)
confirmBtn.layoutChain
.edgesHorzontal(30)
.bottom(35)
.height(50)
return view
}()
lazy var agreementCheckBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "Common/checkbox"), for: .normal)
btn.setImage(UIImage(named: "Common/checkbox_on"), for: .selected)
btn.rx.tap.subscribe(onNext: { [weak btn] in
btn?.isSelected.toggle()
}).disposed(by: disposeBag)
btn.isSelected = true
return btn
}()
lazy var agreementTextView: UITextView = {
let tv = UITextView()
tv.isEditable = false
tv.isScrollEnabled = false
tv.backgroundColor = .clear
tv.textContainerInset = .zero
tv.textContainer.lineFragmentPadding = 0
tv.delegate = self
let text = "购买前请先阅读隐私政策和服务条款"
let attr = NSMutableAttributedString(string: text, attributes: [
.font: UIFont.systemFont(ofSize: 12),
.foregroundColor: UIColor(hexStr: "#999999")
])
let privacyRange = (text as NSString).range(of: "隐私政策")
let termsRange = (text as NSString).range(of: "服务条款")
let linkColor = UIColor(hexStr: "#16B3FF")
attr.addAttributes([.foregroundColor: linkColor, .link: URLManager.shared.privacyPolicyUrl], range: privacyRange)
attr.addAttributes([.foregroundColor: linkColor, .link: URLManager.shared.userAgreementUrl], range: termsRange)
tv.attributedText = attr
tv.linkTextAttributes = [.foregroundColor: linkColor]
return tv
}()
lazy var countdownContainer: UIStackView = {
let stack = UIStackView(arrangedSubviews: [countdownPrefixLabel, countdownMinLabel, countdownColonLabel, countdownSecLabel, countdownSuffixLabel])
stack.axis = .horizontal
stack.alignment = .center
stack.spacing = 0
return stack
}()
lazy var countdownPrefixLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12)
label.textColor = UIColor(hexStr: "#FD501B")
label.text = "优惠活动倒计时 "
return label
}()
lazy var countdownMinLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12)
label.textColor = .white
label.backgroundColor = UIColor(hexStr: "#FD501B")
label.layer.cornerRadius = 2
label.clipsToBounds = true
label.textAlignment = .center
label.text = "15"
return label
}()
lazy var countdownColonLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12)
label.textColor = UIColor(hexStr: "#FD501B")
label.text = ":"
return label
}()
lazy var countdownSecLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12)
label.textColor = .white
label.backgroundColor = UIColor(hexStr: "#FD501B")
label.layer.cornerRadius = 2
label.clipsToBounds = true
label.textAlignment = .center
label.text = "00"
return label
}()
lazy var countdownSuffixLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 12)
label.textColor = UIColor(hexStr: "#FD501B")
label.text = " 限时特惠"
return label
}()
lazy var confirmBtn: 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
}()
private var countdownRemaining: Int = 15 * 60
private var countdownTimer: Timer?
func startCountdown() {
countdownRemaining = 15 * 60
updateCountdown()
countdownTimer?.invalidate()
countdownTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
self?.updateCountdown()
}
}
private func stopCountdown() {
countdownTimer?.invalidate()
countdownTimer = nil
}
private func updateCountdown() {
if countdownRemaining > 0 {
countdownRemaining -= 1
}
else {
AppRouter.shared.popOrDismiss()
return
}
let min = countdownRemaining / 60
let sec = countdownRemaining % 60
countdownMinLabel.text = String(format: "%02d", min)
countdownSecLabel.text = String(format: "%02d", sec)
}
override func layoutSubviews() {
super.layoutSubviews()
}
override func willMove(toSuperview newSuperview: UIView?) {
super.willMove(toSuperview: newSuperview)
if newSuperview == nil {
stopCountdown()
}
}
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: - UIScrollViewDelegate
extension PromotionalActivitiesView: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let maxY = scrollView.contentOffset.y
let alpha = maxY / kNaviHeight
navBarView.alpha = alpha < 0.0 ? 0.0 : alpha
}
}
// MARK: - UITextViewDelegate
extension PromotionalActivitiesView: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
AppRouter.push(Route.web, userInfo: ["url": URL.absoluteString])
return false
}
}
// MARK: - PromotionalNormalCell
class PromotionalNormalCell: UITableViewCell {
func configure(model: VipExpenseModel, isSelected: Bool) {
priceLab.text = model.price
originPriceLab.text = "原价" + model.origin_price
originPriceLab.setupStrikethroughStyle()
goodsNameLab.text = model.goods_name
tipsLab.text = model.tips2
bgView.image = UIImage(named: isSelected ? "PromotionalActivities/normal_on_bg" : "PromotionalActivities/normal_bg")
priceLab.textColor = isSelected ? UIColor(hexStr: "#FF383C") : ThemeManager.shared.color.titleAuxColor
unitLab.textColor = isSelected ? UIColor(hexStr: "#FF383C") : ThemeManager.shared.color.titleAuxColor
}
override init(style: CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
setupSubviews()
}
private func setupSubviews() {
contentView.addSubview(bgView)
bgView.addSubview(unitLab)
bgView.addSubview(priceLab)
bgView.addSubview(originPriceLab)
bgView.addSubview(goodsNameLab)
bgView.addSubview(tipsLab)
bgView.layoutChain
.top(22)
.edgesHorzontal(15)
.bottom()
priceLab.layoutChain
.leftToRightOfView(unitLab, offset: 0)
.centerY()
unitLab.layoutChain
.left(32)
.centerY(bgView, offset: 9)
originPriceLab.layoutChain
.topToBottomOfView(priceLab, offset: -5)
.centerX(priceLab)
goodsNameLab.layoutChain
.leftToRightOfView(priceLab, offset: 27)
.bottomToCenterYOfView(bgView)
tipsLab.layoutChain
.leftToView(goodsNameLab)
.topToCenterYOfView(bgView, offset: 3)
}
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: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var priceLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#FF383C")
label.font = .systemFont(ofSize: 40, weight: .bold)
return label
}()
lazy var unitLab: UILabel = {
let label = UILabel()
label.text = ""
label.textColor = UIColor(hexStr: "#FF383C")
label.font = .systemFont(ofSize: 12, weight: .regular)
return label
}()
lazy var originPriceLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#999999")
label.font = .systemFont(ofSize: 10, weight: .regular)
return label
}()
lazy var goodsNameLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.titleAuxColor
label.font = .systemFont(ofSize: 18, weight: .semibold)
return label
}()
lazy var tipsLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.contentColor
label.font = .systemFont(ofSize: 14, weight: .regular)
return label
}()
}
// MARK: - PromotionalRecommendCell
class PromotionalRecommendCell: UITableViewCell {
func configure(model: VipExpenseModel, isSelected: Bool) {
tipsTitleLab.text = model.tips
priceLab.text = model.price
originPriceLab.text = "原价" + model.origin_price
originPriceLab.setupStrikethroughStyle()
goodsNameLab.text = model.goods_name
tipsLab.text = model.tips2
bgView.image = UIImage(named: isSelected ? "PromotionalActivities/recommend_on_bg" : "PromotionalActivities/recommend_bg")
priceLab.textColor = isSelected ? UIColor(hexStr: "#FF383C") : ThemeManager.shared.color.titleAuxColor
unitLab.textColor = isSelected ? UIColor(hexStr: "#FF383C") : ThemeManager.shared.color.titleAuxColor
}
override init(style: CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
setupSubviews()
}
private func setupSubviews() {
contentView.addSubview(bgView)
bgView.addSubview(unitLab)
bgView.addSubview(priceLab)
bgView.addSubview(originPriceLab)
bgView.addSubview(goodsNameLab)
bgView.addSubview(tipsLab)
bgView.addSubview(recommendLab)
bgView.addSubview(recommendIcon)
bgView.addSubview(tipsTitleView)
tipsTitleView.addSubview(tipsTitleLab)
bgView.layoutChain
.top(22)
.edgesHorzontal(15)
.bottom()
tipsTitleView.layoutChain
.topToView(bgView, offset: -8)
.leftToView(bgView, offset: -6)
.width(94)
.height(35)
tipsTitleLab.layoutChain
.centerX()
.top(5)
priceLab.layoutChain
.leftToRightOfView(unitLab, offset: 0)
.centerY()
unitLab.layoutChain
.left(32)
.centerY(bgView, offset: 9)
originPriceLab.layoutChain
.topToBottomOfView(priceLab, offset: -5)
.centerX(priceLab)
goodsNameLab.layoutChain
.leftToRightOfView(priceLab, offset: 27)
.bottomToCenterYOfView(bgView, offset: -5)
tipsLab.layoutChain
.leftToView(goodsNameLab)
.topToCenterYOfView(bgView, offset: 8)
recommendLab.layoutChain
.top(8)
.right(24)
recommendIcon.layoutChain
.rightToLeftOfView(recommendLab, offset: -3)
.centerY(recommendLab)
.width(13)
.height(11)
}
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: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
view.contentMode = .scaleAspectFill
return view
}()
lazy var priceLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#FF383C")
label.font = .systemFont(ofSize: 40, weight: .bold)
return label
}()
lazy var unitLab: UILabel = {
let label = UILabel()
label.text = ""
label.textColor = UIColor(hexStr: "#FF383C")
label.font = .systemFont(ofSize: 12, weight: .regular)
return label
}()
lazy var originPriceLab: UILabel = {
let label = UILabel()
label.textColor = UIColor(hexStr: "#999999")
label.font = .systemFont(ofSize: 10, weight: .regular)
return label
}()
lazy var goodsNameLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.titleAuxColor
label.font = .systemFont(ofSize: 18, weight: .semibold)
return label
}()
lazy var tipsTitleView: UIImageView = {
let view = UIImageView()
view.backgroundColor = .clear
view.image = UIImage(named: "PromotionalActivities/tips_bg")
return view
}()
lazy var tipsTitleLab: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = .systemFont(ofSize: 12, weight: .semibold)
return label
}()
lazy var tipsLab: UILabel = {
let label = UILabel()
label.textColor = ThemeManager.shared.color.contentColor
label.font = .systemFont(ofSize: 14, weight: .regular)
return label
}()
lazy var recommendIcon: UIImageView = {
let view = UIImageView()
view.contentMode = .scaleAspectFill
view.image = UIImage(named: "PromotionalActivities/recommend_icon")
return view
}()
lazy var recommendLab: UILabel = {
let label = UILabel()
label.text = "80%的用户选择"
label.textColor = .white
label.font = .systemFont(ofSize: 12, weight: .medium)
return label
}()
}