// // FeatureIntroView.swift // QuickLocation // import UIKit 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 = 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 headerBackgroundView.contentMode = .scaleAspectFill headerBackgroundView.clipsToBounds = true addSubview(headerBackgroundView) headerBackgroundView.translatesAutoresizingMaskIntoConstraints = false 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) } NSLayoutConstraint.activate([ headerBackgroundView.topAnchor.constraint(equalTo: topAnchor), headerBackgroundView.leadingAnchor.constraint(equalTo: leadingAnchor), headerBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor), headerBackgroundView.heightAnchor.constraint(equalTo: widthAnchor, multiplier: 230 / 375), titleLineView.widthAnchor.constraint(equalToConstant: 24), titleLineView.heightAnchor.constraint(equalToConstant: 3), titleContainer.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 75), titleContainer.topAnchor.constraint(equalTo: topAnchor, constant: 91), sheetView.topAnchor.constraint(equalTo: topAnchor, constant: 200), sheetView.leadingAnchor.constraint(equalTo: leadingAnchor), sheetView.trailingAnchor.constraint(equalTo: trailingAnchor), sheetView.bottomAnchor.constraint(equalTo: bottomAnchor), 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) } } 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 } } }