// // ImagePreviewViewController.swift // suixinkan // import SnapKit import UIKit /// 图片全屏预览,对齐 Android `MediaPreviewDialog`。 final class ImagePreviewViewController: UIViewController { private let imageURLs: [String] private let startIndex: Int private let scrollView = UIScrollView() private let pageControl = UIPageControl() init(imageURLs: [String], startIndex: Int) { self.imageURLs = imageURLs self.startIndex = min(max(0, startIndex), max(0, imageURLs.count - 1)) super.init(nibName: nil, bundle: nil) modalPresentationStyle = .fullScreen } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .black scrollView.isPagingEnabled = true scrollView.showsHorizontalScrollIndicator = false scrollView.delegate = self pageControl.numberOfPages = imageURLs.count pageControl.currentPage = startIndex pageControl.isHidden = imageURLs.count <= 1 let closeButton = UIButton(type: .system) closeButton.setImage(UIImage(systemName: "xmark"), for: .normal) closeButton.tintColor = .white closeButton.addTarget(self, action: #selector(closeTapped), for: .touchUpInside) view.addSubview(scrollView) view.addSubview(pageControl) view.addSubview(closeButton) scrollView.snp.makeConstraints { make in make.edges.equalToSuperview() } pageControl.snp.makeConstraints { make in make.bottom.equalTo(view.safeAreaLayoutGuide).inset(AppSpacing.md) make.centerX.equalToSuperview() } closeButton.snp.makeConstraints { make in make.top.equalTo(view.safeAreaLayoutGuide).offset(AppSpacing.sm) make.trailing.equalToSuperview().inset(AppSpacing.md) make.size.equalTo(AppSpacing.minTouchTarget) } imageURLs.enumerated().forEach { index, url in let imageView = UIImageView() imageView.contentMode = .scaleAspectFit imageView.loadRemoteImage(urlString: url, placeholderColor: .darkGray) scrollView.addSubview(imageView) imageView.snp.makeConstraints { make in make.top.bottom.equalToSuperview() make.width.equalTo(view.snp.width) make.height.equalTo(view.snp.height) make.leading.equalToSuperview().offset(CGFloat(index) * view.bounds.width) } } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() scrollView.contentSize = CGSize(width: view.bounds.width * CGFloat(imageURLs.count), height: view.bounds.height) scrollView.setContentOffset(CGPoint(x: view.bounds.width * CGFloat(startIndex), y: 0), animated: false) scrollView.subviews.enumerated().forEach { index, subview in subview.frame = CGRect( x: view.bounds.width * CGFloat(index), y: 0, width: view.bounds.width, height: view.bounds.height ) } } @objc private func closeTapped() { dismiss(animated: true) } } extension ImagePreviewViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { guard view.bounds.width > 0 else { return } let page = Int(round(scrollView.contentOffset.x / view.bounds.width)) pageControl.currentPage = page } }