1
This commit is contained in:
parent
2a015361d9
commit
b4c1d9074c
@ -249,6 +249,7 @@
|
|||||||
F3074OOM73GNB5015IC89537 /* HDConfigItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3T20B86PXY9HW2Y7L4511N3 /* HDConfigItem.swift */; };
|
F3074OOM73GNB5015IC89537 /* HDConfigItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3T20B86PXY9HW2Y7L4511N3 /* HDConfigItem.swift */; };
|
||||||
F30E153206675C3SJ3974VL1 /* OJQUnechoSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3J8413H97ZK53EE37TFP314 /* OJQUnechoSectionView.swift */; };
|
F30E153206675C3SJ3974VL1 /* OJQUnechoSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3J8413H97ZK53EE37TFP314 /* OJQUnechoSectionView.swift */; };
|
||||||
F311250SJ7I3DZ74X009990N /* XJSelectorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39X1FMZ9NDT2QB4U8D373J2 /* XJSelectorCell.swift */; };
|
F311250SJ7I3DZ74X009990N /* XJSelectorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39X1FMZ9NDT2QB4U8D373J2 /* XJSelectorCell.swift */; };
|
||||||
|
F3140D182F162CFB003DA73F /* FAPayRetainAlertData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3140D172F162CFB003DA73F /* FAPayRetainAlertData.swift */; };
|
||||||
F31451S3X15B941342J922Q3 /* TConfigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3Z059707KM265K231NMO03T /* TConfigCell.swift */; };
|
F31451S3X15B941342J922Q3 /* TConfigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3Z059707KM265K231NMO03T /* TConfigCell.swift */; };
|
||||||
F31E84U5Y6YW6430Z54X1K40 /* UCHVion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F360D0Y798545M4486S46K5D /* UCHVion.swift */; };
|
F31E84U5Y6YW6430Z54X1K40 /* UCHVion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F360D0Y798545M4486S46K5D /* UCHVion.swift */; };
|
||||||
F31N0S2575E3YC5AOG80WE90 /* TYElyon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36Y0U188W3S4QIX41011QW2 /* TYElyon.swift */; };
|
F31N0S2575E3YC5AOG80WE90 /* TYElyon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36Y0U188W3S4QIX41011QW2 /* TYElyon.swift */; };
|
||||||
@ -627,6 +628,7 @@
|
|||||||
F30R21783575L1F273O32B2I /* DREychainCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DREychainCell.swift; sourceTree = "<group>"; };
|
F30R21783575L1F273O32B2I /* DREychainCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DREychainCell.swift; sourceTree = "<group>"; };
|
||||||
F31320M8CX3D775445170788 /* PYMOastCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PYMOastCell.swift; sourceTree = "<group>"; };
|
F31320M8CX3D775445170788 /* PYMOastCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PYMOastCell.swift; sourceTree = "<group>"; };
|
||||||
F3135K5RQO5DC4S5HWPW523M /* KZOgin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KZOgin.swift; sourceTree = "<group>"; };
|
F3135K5RQO5DC4S5HWPW523M /* KZOgin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KZOgin.swift; sourceTree = "<group>"; };
|
||||||
|
F3140D172F162CFB003DA73F /* FAPayRetainAlertData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAPayRetainAlertData.swift; sourceTree = "<group>"; };
|
||||||
F315105341210LF4533E00H8 /* KCFAlignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KCFAlignment.swift; sourceTree = "<group>"; };
|
F315105341210LF4533E00H8 /* KCFAlignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KCFAlignment.swift; sourceTree = "<group>"; };
|
||||||
F316495030P82IE60B93U07Q /* ADCheckMageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ADCheckMageView.swift; sourceTree = "<group>"; };
|
F316495030P82IE60B93U07Q /* ADCheckMageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ADCheckMageView.swift; sourceTree = "<group>"; };
|
||||||
F31UNU954Q82475250X9P70C /* LKVRecommendedHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LKVRecommendedHomeView.swift; sourceTree = "<group>"; };
|
F31UNU954Q82475250X9P70C /* LKVRecommendedHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LKVRecommendedHomeView.swift; sourceTree = "<group>"; };
|
||||||
@ -770,6 +772,7 @@
|
|||||||
03E9A73F2EB49BE6000D1067 /* FAUpdatesAlert.swift */,
|
03E9A73F2EB49BE6000D1067 /* FAUpdatesAlert.swift */,
|
||||||
03E9A7472EB5D2CB000D1067 /* FALogoutAlert.swift */,
|
03E9A7472EB5D2CB000D1067 /* FALogoutAlert.swift */,
|
||||||
035589322F161E6E00FAEF4A /* FAPayRetainAlert.swift */,
|
035589322F161E6E00FAEF4A /* FAPayRetainAlert.swift */,
|
||||||
|
F3140D172F162CFB003DA73F /* FAPayRetainAlertData.swift */,
|
||||||
);
|
);
|
||||||
path = Alert;
|
path = Alert;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2192,6 +2195,7 @@
|
|||||||
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */,
|
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */,
|
||||||
039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */,
|
039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */,
|
||||||
F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */,
|
F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */,
|
||||||
|
F3140D182F162CFB003DA73F /* FAPayRetainAlertData.swift in Sources */,
|
||||||
F3Q234J5M18F1Q5G2948P056 /* NPVBoutModalController.swift in Sources */,
|
F3Q234J5M18F1Q5G2948P056 /* NPVBoutModalController.swift in Sources */,
|
||||||
F38Y7NBX3M0RE4O142264411 /* EZEFlow.swift in Sources */,
|
F38Y7NBX3M0RE4O142264411 /* EZEFlow.swift in Sources */,
|
||||||
F363P024H4W1T8LN2546W883 /* YBanner.swift in Sources */,
|
F363P024H4W1T8LN2546W883 /* YBanner.swift in Sources */,
|
||||||
|
|||||||
@ -6,51 +6,444 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import SnapKit
|
||||||
|
|
||||||
class FAPayRetainAlert: FABaseAlert {
|
class FAPayRetainAlert: FABaseAlert {
|
||||||
|
|
||||||
|
private var selectedIndex = FAPayRetainAlertData.defaultSelectedIndex
|
||||||
|
|
||||||
private lazy var bgView: UIImageView = {
|
private lazy var bgView: UIImageView = {
|
||||||
let imageView = UIImageView(image: UIImage(named: "pay_retain_bg_image"))
|
let imageView = UIImageView(image: UIImage(named: FAPayRetainAlertData.Assets.background))
|
||||||
|
imageView.contentMode = .scaleToFill
|
||||||
|
imageView.isUserInteractionEnabled = true
|
||||||
return imageView
|
return imageView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var titleLabel: UILabel = {
|
private lazy var titleLabel: FALabel = {
|
||||||
let label = UILabel()
|
let label = FALabel()
|
||||||
|
label.text = FAPayRetainAlertData.titleText
|
||||||
|
label.font = .font(ofSize: 44, weight: .init(900)).withBoldItalic()
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
label.textColors = [
|
||||||
|
UIColor.fa_hex(0x0178FF).cgColor,
|
||||||
|
UIColor.fa_hex(0x81CAFF).cgColor
|
||||||
|
]
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var countdownView: PayRetainCountdownView = {
|
||||||
|
let view = PayRetainCountdownView()
|
||||||
|
view.update(prefix: FAPayRetainAlertData.countdownPrefix,
|
||||||
|
countdown: FAPayRetainAlertData.countdown,
|
||||||
|
suffix: FAPayRetainAlertData.countdownSuffix)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bonusTagView: PayRetainBonusTagView = {
|
||||||
|
let view = PayRetainBonusTagView()
|
||||||
|
view.update(text: FAPayRetainAlertData.bonusTitle)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: UICollectionView = {
|
||||||
|
let layout = UICollectionViewFlowLayout()
|
||||||
|
layout.scrollDirection = .vertical
|
||||||
|
layout.minimumLineSpacing = FAPayRetainAlertData.Layout.packItemSpacing
|
||||||
|
layout.minimumInteritemSpacing = 0
|
||||||
|
layout.itemSize = FAPayRetainAlertData.Layout.packItemSize
|
||||||
|
|
||||||
|
let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
|
view.backgroundColor = .clear
|
||||||
|
view.isScrollEnabled = false
|
||||||
|
view.showsVerticalScrollIndicator = false
|
||||||
|
view.dataSource = self
|
||||||
|
view.delegate = self
|
||||||
|
view.register(FAPayRetainPackCell.self, forCellWithReuseIdentifier: FAPayRetainPackCell.reuseIdentifier)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
|
collectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor required init?(coder: NSCoder) {
|
@MainActor required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FAPayRetainAlert {
|
extension FAPayRetainAlert {
|
||||||
|
|
||||||
private func fa_setupLayout() {
|
private func fa_setupLayout() {
|
||||||
|
contentWidth = FAPayRetainAlertData.Layout.contentWidth
|
||||||
contentView.backgroundColor = .clear
|
contentView.backgroundColor = .clear
|
||||||
contentView.layer.cornerRadius = 0
|
contentView.layer.cornerRadius = FAPayRetainAlertData.Layout.cardCornerRadius
|
||||||
|
contentView.layer.masksToBounds = true
|
||||||
|
closeButton.layer.cornerRadius = 12
|
||||||
|
closeButton.layer.masksToBounds = true
|
||||||
|
closeButton.layer.borderWidth = 1.3
|
||||||
|
closeButton.layer.borderColor = UIColor.fa_hex(0xCACACA).cgColor
|
||||||
|
closeButton.tintColor = UIColor.fa_hex(0xCACACA)
|
||||||
|
|
||||||
contentView.addSubview(bgView)
|
contentView.addSubview(bgView)
|
||||||
contentView.addSubview(titleLabel)
|
contentView.addSubview(titleLabel)
|
||||||
|
contentView.addSubview(countdownView)
|
||||||
|
contentView.addSubview(bonusTagView)
|
||||||
|
contentView.addSubview(collectionView)
|
||||||
|
|
||||||
|
|
||||||
bgView.snp.makeConstraints { make in
|
bgView.snp.makeConstraints { make in
|
||||||
make.edges.equalToSuperview()
|
make.edges.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.top.equalToSuperview().offset(160)
|
make.top.equalToSuperview().offset(FAPayRetainAlertData.Layout.titleTop)
|
||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
make.right.lessThanOrEqualToSuperview().offset(-1)
|
make.right.lessThanOrEqualToSuperview().offset(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
countdownView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(FAPayRetainAlertData.Layout.countdownLeft)
|
||||||
|
make.top.equalToSuperview().offset(FAPayRetainAlertData.Layout.countdownTop)
|
||||||
|
}
|
||||||
|
|
||||||
|
bonusTagView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(FAPayRetainAlertData.Layout.bonusTagLeft)
|
||||||
|
make.top.equalToSuperview().offset(FAPayRetainAlertData.Layout.bonusTagTop)
|
||||||
|
make.height.equalTo(FAPayRetainAlertData.Layout.bonusTagHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(FAPayRetainAlertData.Layout.packListLeft)
|
||||||
|
make.top.equalToSuperview().offset(FAPayRetainAlertData.Layout.packListTop)
|
||||||
|
make.width.equalTo(FAPayRetainAlertData.Layout.packItemSize.width)
|
||||||
|
make.height.equalTo(FAPayRetainAlertData.Layout.packListHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
closeButton.snp.updateConstraints { make in
|
||||||
|
make.width.height.equalTo(24)
|
||||||
|
}
|
||||||
|
|
||||||
|
contentView.snp.makeConstraints { make in
|
||||||
|
make.height.equalTo(FAPayRetainAlertData.Layout.contentHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - UICollectionViewDataSource & Delegate
|
||||||
|
extension FAPayRetainAlert: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return FAPayRetainAlertData.packItems.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FAPayRetainPackCell.reuseIdentifier, for: indexPath) as! FAPayRetainPackCell
|
||||||
|
let item = FAPayRetainAlertData.packItems[indexPath.item]
|
||||||
|
cell.configure(with: item, isSelected: indexPath.item == selectedIndex)
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
|
selectedIndex = indexPath.item
|
||||||
|
collectionView.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Subviews
|
||||||
|
extension FAPayRetainAlert {
|
||||||
|
final class PayRetainCountdownView: UIView {
|
||||||
|
private let prefixLabel = UILabel()
|
||||||
|
private let suffixLabel = UILabel()
|
||||||
|
private let timeStackView = UIStackView()
|
||||||
|
private let hourView = TimeBoxView()
|
||||||
|
private let minuteView = TimeBoxView()
|
||||||
|
private let secondView = TimeBoxView()
|
||||||
|
private let colonLabel1 = UILabel()
|
||||||
|
private let colonLabel2 = UILabel()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新倒计时显示内容
|
||||||
|
func update(prefix: String, countdown: FAPayRetainAlertData.Countdown, suffix: String) {
|
||||||
|
prefixLabel.text = prefix
|
||||||
|
suffixLabel.text = suffix
|
||||||
|
hourView.setText(countdown.hours)
|
||||||
|
minuteView.setText(countdown.minutes)
|
||||||
|
secondView.setText(countdown.seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupView() {
|
||||||
|
let mainStack = UIStackView()
|
||||||
|
mainStack.axis = .horizontal
|
||||||
|
mainStack.alignment = .center
|
||||||
|
mainStack.spacing = 5
|
||||||
|
|
||||||
|
prefixLabel.font = .font(ofSize: 12, weight: .medium).withBoldItalic()
|
||||||
|
prefixLabel.textColor = UIColor.fa_hex(0x0F0F0F)
|
||||||
|
|
||||||
|
suffixLabel.font = .font(ofSize: 12, weight: .medium).withBoldItalic()
|
||||||
|
suffixLabel.textColor = UIColor.fa_hex(0x0F0F0F)
|
||||||
|
|
||||||
|
timeStackView.axis = .horizontal
|
||||||
|
timeStackView.alignment = .center
|
||||||
|
timeStackView.spacing = 3
|
||||||
|
|
||||||
|
colonLabel1.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
colonLabel1.textColor = UIColor.fa_hex(0x0F0F0F)
|
||||||
|
colonLabel1.text = ":"
|
||||||
|
|
||||||
|
colonLabel2.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
colonLabel2.textColor = UIColor.fa_hex(0x0F0F0F)
|
||||||
|
colonLabel2.text = ":"
|
||||||
|
|
||||||
|
timeStackView.addArrangedSubview(hourView)
|
||||||
|
timeStackView.addArrangedSubview(colonLabel1)
|
||||||
|
timeStackView.addArrangedSubview(minuteView)
|
||||||
|
timeStackView.addArrangedSubview(colonLabel2)
|
||||||
|
timeStackView.addArrangedSubview(secondView)
|
||||||
|
|
||||||
|
addSubview(mainStack)
|
||||||
|
mainStack.addArrangedSubview(prefixLabel)
|
||||||
|
mainStack.addArrangedSubview(timeStackView)
|
||||||
|
mainStack.addArrangedSubview(suffixLabel)
|
||||||
|
|
||||||
|
mainStack.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TimeBoxView: UIView {
|
||||||
|
private let label = UILabel()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setText(_ text: String) {
|
||||||
|
label.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupView() {
|
||||||
|
backgroundColor = UIColor.fa_hex(0x0F0F0F)
|
||||||
|
layer.cornerRadius = 4
|
||||||
|
layer.masksToBounds = true
|
||||||
|
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
label.textAlignment = .center
|
||||||
|
|
||||||
|
addSubview(label)
|
||||||
|
label.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
snp.makeConstraints { make in
|
||||||
|
make.width.height.equalTo(18)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class PayRetainBonusTagView: UIView {
|
||||||
|
private let stackView = UIStackView()
|
||||||
|
private let leftStar = UIImageView(image: UIImage(named: FAPayRetainAlertData.Assets.starIcon))
|
||||||
|
private let rightStar = UIImageView(image: UIImage(named: FAPayRetainAlertData.Assets.starIcon))
|
||||||
|
private let titleLabel = UILabel()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新标签文案
|
||||||
|
func update(text: String) {
|
||||||
|
titleLabel.text = text
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupView() {
|
||||||
|
backgroundColor = UIColor.fa_hex(0x20A1FF)
|
||||||
|
layer.cornerRadius = 10
|
||||||
|
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]
|
||||||
|
|
||||||
|
stackView.axis = .horizontal
|
||||||
|
stackView.alignment = .center
|
||||||
|
stackView.spacing = 5
|
||||||
|
|
||||||
|
titleLabel.font = .font(ofSize: 20, weight: .bold).withBoldItalic()
|
||||||
|
titleLabel.textColor = .FFFFFF
|
||||||
|
|
||||||
|
[leftStar, titleLabel, rightStar].forEach { stackView.addArrangedSubview($0) }
|
||||||
|
[leftStar, rightStar].forEach { imageView in
|
||||||
|
imageView.contentMode = .scaleAspectFit
|
||||||
|
imageView.snp.makeConstraints { make in
|
||||||
|
make.width.height.equalTo(9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addSubview(stackView)
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(8)
|
||||||
|
make.right.equalToSuperview().offset(-8)
|
||||||
|
make.top.equalToSuperview().offset(4)
|
||||||
|
make.bottom.equalToSuperview().offset(-4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Pack Cell
|
||||||
|
final class FAPayRetainPackCell: UICollectionViewCell {
|
||||||
|
static let reuseIdentifier = "FAPayRetainPackCell"
|
||||||
|
|
||||||
|
private let bgView = FAGradientView()
|
||||||
|
private let selectedBorderView = UIView()
|
||||||
|
private let giftImageView = UIImageView(image: UIImage(named: FAPayRetainAlertData.Assets.giftIcon))
|
||||||
|
private let coinIconView = UIImageView(image: UIImage(named: FAPayRetainAlertData.Assets.coinIcon))
|
||||||
|
private let coinLabel = UILabel()
|
||||||
|
private let bonusLabel = UILabel()
|
||||||
|
private let priceView = FAGradientView()
|
||||||
|
private let priceLabel = UILabel()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定套餐数据和选中状态
|
||||||
|
func configure(with item: FAPayRetainAlertData.PackItem, isSelected: Bool) {
|
||||||
|
coinLabel.text = "\(item.coinCount)"
|
||||||
|
bonusLabel.text = item.bonusText
|
||||||
|
priceLabel.text = item.priceText
|
||||||
|
selectedBorderView.isHidden = !isSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupView() {
|
||||||
|
contentView.backgroundColor = .clear
|
||||||
|
|
||||||
|
bgView.fa_colors = [
|
||||||
|
UIColor.fa_hex(0xF6F9FF).cgColor,
|
||||||
|
UIColor.fa_hex(0x4583FF).cgColor
|
||||||
|
]
|
||||||
|
bgView.fa_locations = [0, 1]
|
||||||
|
bgView.fa_startPoint = .init(x: 0.5, y: 0)
|
||||||
|
bgView.fa_endPoint = .init(x: 0.5, y: 1)
|
||||||
|
bgView.layer.cornerRadius = 15
|
||||||
|
bgView.layer.masksToBounds = true
|
||||||
|
|
||||||
|
selectedBorderView.layer.cornerRadius = 15
|
||||||
|
selectedBorderView.layer.borderWidth = 2
|
||||||
|
selectedBorderView.layer.borderColor = UIColor.fa_hex(0x1F8FFF).cgColor
|
||||||
|
selectedBorderView.isHidden = true
|
||||||
|
|
||||||
|
giftImageView.contentMode = .scaleAspectFit
|
||||||
|
|
||||||
|
coinIconView.contentMode = .scaleAspectFit
|
||||||
|
|
||||||
|
coinLabel.font = .font(ofSize: 22, weight: .bold)
|
||||||
|
coinLabel.textColor = UIColor.fa_hex(0x276CFF)
|
||||||
|
|
||||||
|
bonusLabel.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
bonusLabel.textColor = .FFFFFF
|
||||||
|
|
||||||
|
priceView.fa_colors = [
|
||||||
|
UIColor.fa_hex(0x3071FF).cgColor,
|
||||||
|
UIColor.fa_hex(0x4583FF).cgColor
|
||||||
|
]
|
||||||
|
priceView.fa_locations = [0, 1]
|
||||||
|
priceView.fa_startPoint = .init(x: 0, y: 0.5)
|
||||||
|
priceView.fa_endPoint = .init(x: 1, y: 0.5)
|
||||||
|
priceView.layer.cornerRadius = FAPayRetainAlertData.Layout.priceSize.height / 2
|
||||||
|
priceView.layer.masksToBounds = true
|
||||||
|
priceView.layer.borderWidth = 1
|
||||||
|
priceView.layer.borderColor = UIColor.fa_hex(0xFFFFFF).cgColor
|
||||||
|
|
||||||
|
priceLabel.font = .font(ofSize: 22, weight: .bold)
|
||||||
|
priceLabel.textColor = .FFFFFF
|
||||||
|
|
||||||
|
let coinStack = UIStackView(arrangedSubviews: [coinIconView, coinLabel])
|
||||||
|
coinStack.axis = .horizontal
|
||||||
|
coinStack.alignment = .center
|
||||||
|
coinStack.spacing = 2
|
||||||
|
|
||||||
|
contentView.addSubview(bgView)
|
||||||
|
contentView.addSubview(selectedBorderView)
|
||||||
|
bgView.addSubview(giftImageView)
|
||||||
|
bgView.addSubview(coinStack)
|
||||||
|
bgView.addSubview(bonusLabel)
|
||||||
|
bgView.addSubview(priceView)
|
||||||
|
priceView.addSubview(priceLabel)
|
||||||
|
|
||||||
|
bgView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedBorderView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
giftImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(6)
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.width.height.equalTo(FAPayRetainAlertData.Layout.giftSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinStack.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(FAPayRetainAlertData.Layout.coinStackLeft)
|
||||||
|
make.top.equalToSuperview().offset(FAPayRetainAlertData.Layout.coinStackTop)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinIconView.snp.makeConstraints { make in
|
||||||
|
make.width.height.equalTo(22)
|
||||||
|
}
|
||||||
|
|
||||||
|
bonusLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(coinStack)
|
||||||
|
make.top.equalTo(coinStack.snp.bottom).offset(FAPayRetainAlertData.Layout.bonusTopSpacing)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceView.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-14)
|
||||||
|
make.top.equalToSuperview().offset(FAPayRetainAlertData.Layout.priceTop)
|
||||||
|
make.size.equalTo(FAPayRetainAlertData.Layout.priceSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension UIColor {
|
||||||
|
// 统一十六进制色值转换,便于对齐设计稿
|
||||||
|
static func fa_hex(_ hex: UInt32, alpha: CGFloat = 1) -> UIColor {
|
||||||
|
let red = CGFloat((hex >> 16) & 0xFF) / 255.0
|
||||||
|
let green = CGFloat((hex >> 8) & 0xFF) / 255.0
|
||||||
|
let blue = CGFloat(hex & 0xFF) / 255.0
|
||||||
|
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
74
Fableon/Object/Libs/Alert/FAPayRetainAlertData.swift
Normal file
74
Fableon/Object/Libs/Alert/FAPayRetainAlertData.swift
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// FAPayRetainAlertData.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2026/1/13.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
enum FAPayRetainAlertData {
|
||||||
|
// 弹窗文案与列表数据统一管理,避免在视图内部硬编码
|
||||||
|
static let titleText = "Exclusive Gift"
|
||||||
|
static let countdownPrefix = "Last"
|
||||||
|
static let countdownSuffix = "Don't Miss Out!"
|
||||||
|
static let bonusTitle = "New User Bonus Bundle"
|
||||||
|
|
||||||
|
static let countdown = Countdown(hours: "03", minutes: "29", seconds: "55")
|
||||||
|
|
||||||
|
static let packItems: [PackItem] = [
|
||||||
|
PackItem(coinCount: 3500, bonusText: "+700 free coins", priceText: "$4.99"),
|
||||||
|
PackItem(coinCount: 3500, bonusText: "+700 free coins", priceText: "$4.99"),
|
||||||
|
PackItem(coinCount: 3500, bonusText: "+700 free coins", priceText: "$4.99")
|
||||||
|
]
|
||||||
|
|
||||||
|
static let defaultSelectedIndex = 2
|
||||||
|
static let defaultCenterIndex = 1
|
||||||
|
|
||||||
|
struct Countdown {
|
||||||
|
let hours: String
|
||||||
|
let minutes: String
|
||||||
|
let seconds: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PackItem {
|
||||||
|
let coinCount: Int
|
||||||
|
let bonusText: String
|
||||||
|
let priceText: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Assets {
|
||||||
|
// 资源名集中管理,便于从 Assets.xcassets 替换
|
||||||
|
static let background = "pay_retain_bg_image"
|
||||||
|
static let giftIcon = "pay_retain_gift"
|
||||||
|
static let coinIcon = "pay_retain_coin"
|
||||||
|
static let starIcon = "pay_retain_star"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Layout {
|
||||||
|
// 设计稿对应的尺寸/间距配置
|
||||||
|
static let contentWidth: CGFloat = 326
|
||||||
|
static let contentHeight: CGFloat = 515
|
||||||
|
static let cardCornerRadius: CGFloat = 22
|
||||||
|
|
||||||
|
static let titleTop: CGFloat = 30
|
||||||
|
static let countdownTop: CGFloat = 72
|
||||||
|
static let countdownLeft: CGFloat = 10
|
||||||
|
static let bonusTagTop: CGFloat = 105
|
||||||
|
static let bonusTagLeft: CGFloat = 22
|
||||||
|
static let bonusTagHeight: CGFloat = 24
|
||||||
|
|
||||||
|
static let packListTop: CGFloat = 152
|
||||||
|
static let packListLeft: CGFloat = 10
|
||||||
|
static let packItemSize = CGSize(width: 306, height: 68)
|
||||||
|
static let packItemSpacing: CGFloat = 10
|
||||||
|
static let packListHeight: CGFloat = 224
|
||||||
|
|
||||||
|
static let priceSize = CGSize(width: 97, height: 40)
|
||||||
|
static let priceTop: CGFloat = 14
|
||||||
|
static let coinStackLeft: CGFloat = 62
|
||||||
|
static let coinStackTop: CGFloat = 15
|
||||||
|
static let bonusTopSpacing: CGFloat = 5
|
||||||
|
static let giftSize: CGFloat = 46
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user