// // 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 } } }