252 lines
9.0 KiB
Swift
252 lines
9.0 KiB
Swift
//
|
|
// FeatureIntroView.swift
|
|
// QuickLocation
|
|
//
|
|
|
|
import UIKit
|
|
import SDCycleScrollView
|
|
|
|
struct FeatureIntroItem {
|
|
let imageName: String
|
|
let accessibilityTitle: String
|
|
let aspectRatio: CGFloat
|
|
let action: FeatureIntroAction
|
|
}
|
|
|
|
enum FeatureIntroAction {
|
|
case signIn
|
|
case createBubble
|
|
case lockDistract
|
|
case pigeonMessage
|
|
case searchLocation
|
|
case sos
|
|
case placeholder
|
|
}
|
|
|
|
final class FeatureIntroView: UIView {
|
|
|
|
var onTapItem: ((FeatureIntroAction) -> Void)?
|
|
|
|
private let headerBackgroundView = UIView()
|
|
private let headerBgImg = UIImageView(image: UIImage(named: "Explore/header_bg"))
|
|
private let titleContainer = UIStackView()
|
|
private let titleLineView = UIView()
|
|
private let titleLabel = UILabel()
|
|
private let sheetView = UIView()
|
|
private let scrollView = UIScrollView()
|
|
private let contentView = UIView()
|
|
private let gridStack = UIStackView()
|
|
|
|
private let items: [FeatureIntroItem] = [
|
|
FeatureIntroItem(
|
|
imageName: "Explore/sign_in_card",
|
|
accessibilityTitle: "还在吗",
|
|
aspectRatio: 127 / 166,
|
|
action: .signIn
|
|
),
|
|
FeatureIntroItem(
|
|
imageName: "Explore/pigeon_message_card",
|
|
accessibilityTitle: "飞鸽传书",
|
|
aspectRatio: 127 / 166,
|
|
action: .pigeonMessage
|
|
),
|
|
FeatureIntroItem(
|
|
imageName: "Explore/lock_distract_card",
|
|
accessibilityTitle: "一键锁机",
|
|
aspectRatio: 130 / 166,
|
|
action: .lockDistract
|
|
),
|
|
FeatureIntroItem(
|
|
imageName: "Explore/bubble_card",
|
|
accessibilityTitle: "隐身气泡",
|
|
aspectRatio: 130 / 166,
|
|
action: .createBubble
|
|
),
|
|
FeatureIntroItem(
|
|
imageName: "Explore/search_location_card",
|
|
accessibilityTitle: "查位置",
|
|
aspectRatio: 130 / 166,
|
|
action: .searchLocation
|
|
),
|
|
FeatureIntroItem(
|
|
imageName: "Explore/sos_card",
|
|
accessibilityTitle: "SOS",
|
|
aspectRatio: 130 / 166,
|
|
action: .sos
|
|
)
|
|
]
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setupUI()
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
private func setupUI() {
|
|
backgroundColor = .white
|
|
|
|
addSubview(headerBackgroundView)
|
|
headerBackgroundView.backgroundColor = .clear
|
|
|
|
headerBgImg.contentMode = .scaleAspectFill
|
|
headerBgImg.clipsToBounds = true
|
|
headerBackgroundView.addSubview(headerBgImg)
|
|
headerBackgroundView.addSubview(cycleScrollView)
|
|
|
|
titleLineView.backgroundColor = UIColor(hexStr: "#253B55")
|
|
titleLineView.layer.cornerRadius = 1.5
|
|
titleLineView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
titleLabel.text = "一键锁机"
|
|
titleLabel.textColor = UIColor(hexStr: "#253B55")
|
|
titleLabel.font = FontManager.ziHunBianHei(28)
|
|
titleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
|
|
|
titleContainer.axis = .horizontal
|
|
titleContainer.alignment = .center
|
|
titleContainer.spacing = 3
|
|
titleContainer.addArrangedSubview(titleLineView)
|
|
titleContainer.addArrangedSubview(titleLabel)
|
|
addSubview(titleContainer)
|
|
titleContainer.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
sheetView.backgroundColor = .white
|
|
sheetView.layer.cornerRadius = 30
|
|
sheetView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
|
sheetView.clipsToBounds = true
|
|
addSubview(sheetView)
|
|
sheetView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
scrollView.alwaysBounceVertical = false
|
|
scrollView.showsVerticalScrollIndicator = false
|
|
scrollView.contentInset.bottom = 90
|
|
sheetView.addSubview(scrollView)
|
|
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
scrollView.addSubview(contentView)
|
|
contentView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
gridStack.axis = .vertical
|
|
gridStack.alignment = .fill
|
|
gridStack.distribution = .fill
|
|
gridStack.spacing = 13
|
|
contentView.addSubview(gridStack)
|
|
gridStack.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
for rowIndex in 0..<3 {
|
|
let rowStack = UIStackView()
|
|
rowStack.axis = .horizontal
|
|
rowStack.alignment = .fill
|
|
rowStack.distribution = .fillEqually
|
|
rowStack.spacing = 13
|
|
|
|
for columnIndex in 0..<2 {
|
|
let itemIndex = rowIndex * 2 + columnIndex
|
|
let item = items[itemIndex]
|
|
let card = FeatureIntroCardView(item: item)
|
|
card.tag = itemIndex
|
|
card.addTarget(self, action: #selector(cardTapped(_:)), for: .touchUpInside)
|
|
rowStack.addArrangedSubview(card)
|
|
card.heightAnchor.constraint(equalTo: card.widthAnchor, multiplier: item.aspectRatio).isActive = true
|
|
}
|
|
gridStack.addArrangedSubview(rowStack)
|
|
}
|
|
|
|
headerBackgroundView.layoutChain
|
|
.edges(excludingEdge: .bottom)
|
|
.heightToWidth(230 / 375)
|
|
|
|
headerBgImg.layoutChain.edges()
|
|
|
|
cycleScrollView.layoutChain.edges()
|
|
|
|
sheetView.layoutChain
|
|
.topToBottomOfView(headerBackgroundView, offset: -30)
|
|
.edges(excludingEdge: .top)
|
|
|
|
NSLayoutConstraint.activate([
|
|
titleLineView.widthAnchor.constraint(equalToConstant: 24),
|
|
titleLineView.heightAnchor.constraint(equalToConstant: 3),
|
|
titleContainer.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 75),
|
|
titleContainer.topAnchor.constraint(equalTo: topAnchor, constant: 91),
|
|
|
|
scrollView.topAnchor.constraint(equalTo: sheetView.topAnchor),
|
|
scrollView.leadingAnchor.constraint(equalTo: sheetView.leadingAnchor),
|
|
scrollView.trailingAnchor.constraint(equalTo: sheetView.trailingAnchor),
|
|
scrollView.bottomAnchor.constraint(equalTo: sheetView.bottomAnchor),
|
|
|
|
contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
|
|
contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
|
|
contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
|
|
contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
|
|
contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
|
|
|
|
gridStack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 19),
|
|
gridStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
|
|
gridStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
|
|
gridStack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20)
|
|
])
|
|
}
|
|
|
|
@objc private func cardTapped(_ sender: FeatureIntroCardView) {
|
|
guard items.indices.contains(sender.tag) else { return }
|
|
onTapItem?(items[sender.tag].action)
|
|
}
|
|
|
|
// MARK: - 轮播图
|
|
lazy var cycleScrollView: SDCycleScrollView = {
|
|
let view = SDCycleScrollView(frame: .zero)
|
|
view.backgroundColor = .clear
|
|
view.scrollDirection = .horizontal
|
|
// view.showPageControl = true
|
|
view.bannerImageViewContentMode = .scaleAspectFill
|
|
view.autoScrollTimeInterval = 5
|
|
// view.currentPageDotColor = UIColor(hexStr: "#16B3FF")
|
|
// view.pageDotColor = UIColor(hexStr: "#7AD6FF").withAlphaComponent(0.4)
|
|
// view.pageControlDotSize = CGSize(width: 8, height: 8)
|
|
view.clipsToBounds = false
|
|
// view.pageControlBottomOffset = -34
|
|
view.isHidden = true
|
|
return view
|
|
}()
|
|
}
|
|
|
|
final class FeatureIntroCardView: UIControl {
|
|
|
|
private let imageView = UIImageView()
|
|
|
|
init(item: FeatureIntroItem) {
|
|
super.init(frame: .zero)
|
|
|
|
isAccessibilityElement = true
|
|
accessibilityLabel = item.accessibilityTitle
|
|
accessibilityTraits = .button
|
|
|
|
imageView.image = UIImage(named: item.imageName)
|
|
imageView.contentMode = .scaleAspectFit
|
|
imageView.isUserInteractionEnabled = false
|
|
addSubview(imageView)
|
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
NSLayoutConstraint.activate([
|
|
imageView.topAnchor.constraint(equalTo: topAnchor),
|
|
imageView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
imageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
imageView.bottomAnchor.constraint(equalTo: bottomAnchor)
|
|
])
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override var isHighlighted: Bool {
|
|
didSet {
|
|
imageView.alpha = isHighlighted ? 0.78 : 1
|
|
}
|
|
}
|
|
}
|