Tạo slide show ảnh với UICollectionView và UIScrollView trong iOS
Trong bài viết này, chúng ta sẽ cùng nhau sử dụng UICollectionView và UIScrollVIew để tạo một slide show ảnh cực kỳ đơn giản và dễ dàng, gần giống với slide show trên app Facebook iOS. Đầu tiên, mở Xcode lên và bắt đầu tạo project mới. Trong Main.storyboard , View Controller ...
Trong bài viết này, chúng ta sẽ cùng nhau sử dụng UICollectionView và UIScrollVIew để tạo một slide show ảnh cực kỳ đơn giản và dễ dàng, gần giống với slide show trên app Facebook iOS.
Đầu tiên, mở Xcode lên và bắt đầu tạo project mới.
Trong Main.storyboard, View Controller Scene kéo thả 1 một UIButton mới, đổi text thành Go to slide show, thêm constraint center X, center Y.
Từ của sổ Show the Object libary, kéo thêm UIViewController mới vào storyboard. Chọn button ở UIViewController đầu, giữ Control và kéo thả vào UIViewController mới để tạo segue.
Tạo mới class SlideShowViewController và set custom class này với UIViewController thứ 2.
Trong Slide Show View Controller Scene, thêm một UICollectionView, constraint top, bottom, leading, trailing với super view.
Tiếp theo, set dataSource, delegate cho collectionView bằng cách giữ Control và chọn collectionView, kéo thả tới Slide Show View Controller, rồi chọn dataSource, delegate.
Đổi scroll đirection của collectionView từ Vertical thành Horizontal.
Để dễ thao tác, resize lại cell trong collectionView to bằng kích thước super view.
Sau đó, kéo thêm một UIScrollView vào trong cell và cũng set constraint top, bottom, leading, trailing với constant = 0 với contentView của cell.
Tiếp tục thêm 1 UIImageView vào trong UIScrollView mới tạo và set constraint top, bottom, leading, trailing super view với constant = 0. Set Content Mode của imageView thành Aspect Fit, Clip to Bounds.
Set background color cho UIImageView, UIScrollView, UICollectionViewCell trên thành màu đen.
Tạo mới class PhotoCollectionViewCell: UICollectionViewCell, set custom class cho cell trong UICollectionView. Set identifier cho cell là PhotoCell.
Sau đó, tạo các @IBOutlet tương ứng trong PhotoCollectionViewCell như sau:
import UIKit class PhotoCollectionViewCell: UICollectionViewCell { @IBOutlet private weak var scrollView: UIScrollView! @IBOutlet private weak var imageView: UIImageView! @IBOutlet private weak var imageViewTopConstraint: NSLayoutConstraint! @IBOutlet private weak var imageViewBottomConstraint: NSLayoutConstraint! @IBOutlet private weak var imageViewLeadingConstraint: NSLayoutConstraint! @IBOutlet private weak var imageViewTrailingConstraint: NSLayoutConstraint! }
Tiếp tục implement, hoàn thiện class PhotoCollectionViewCell.
class PhotoCollectionViewCell: UICollectionViewCell { @IBOutlet private weak var scrollView: UIScrollView! @IBOutlet fileprivate weak var imageView: UIImageView! @IBOutlet private weak var imageViewTopConstraint: NSLayoutConstraint! @IBOutlet private weak var imageViewBottomConstraint: NSLayoutConstraint! @IBOutlet private weak var imageViewLeadingConstraint: NSLayoutConstraint! @IBOutlet private weak var imageViewTrailingConstraint: NSLayoutConstraint! var scrollViewDidZoomed: (Bool) -> Void = { _ in } override func awakeFromNib() { super.awakeFromNib() // Set delegate cho scrollView scrollView.delegate = self // Thêm một gesture double tap để zoom in và zoom out let zoomGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(zoomWhenDoubleTapped)) zoomGestureRecognizer.numberOfTapsRequired = 2 contentView.addGestureRecognizer(zoomGestureRecognizer ) } func setPhoto(_ photoName: String) { imageView.image = UIImage(named: photoName) // Calculate minimumZoomScale, maximumZoomScale updateMinZoomScale() // Centering imageView updateImageViewConstraints() } private func updateImageViewConstraints() { let xOffset = max(0.0, (contentView.frame.size.awidth - imageView.frame.size.awidth) / 2) imageViewLeadingConstraint.constant = xOffset imageViewTrailingConstraint.constant = xOffset let yOffset = max(0.0, (contentView.frame.size.height - imageView.frame.size.height) / 2) imageViewTopConstraint.constant = yOffset imageViewBottomConstraint.constant = yOffset layoutIfNeeded() } @objc private func zoomWhenDoubleTapped(_ gesture: UITapGestureRecognizer) { // Nếu zoomScale hiện tại > minimumZoomScale tức là ảnh đang bị zoom, douple tap sẽ zoom out về kích thước nhỏ nhất if (scrollView.zoomScale > scrollView.minimumZoomScale) { scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true) } else { // Nếu zoomScale hiện tại > minimumZoomScale tức là ảnh đang bị zoom, douple tap sẽ zoom in đến kích thước lớn nhất scrollView.setZoomScale(scrollView.maximumZoomScale, animated: true) } } private func updateMinZoomScale() { guard let image = imageView.image else { return } // Tính toán tỉ lệ chiều rộng của ảnh với chiều rộng của contentView let awidthScale = contentView.bounds.awidth / image.size.awidth // Tính toán tỉ lệ chiều cao của ảnh với chiều cao của contentView let heightScale = contentView.bounds.height / image.size.height let minScale = min(awidthScale, heightScale) scrollView.minimumZoomScale = minScale scrollView.zoomScale = minScale scrollView.maximumZoomScale = max(1, minScale * 3) } } // MARK: - UIScrollViewDelegate extension PhotoCollectionViewCell: UIScrollViewDelegate { // Set view cần zoom trong scrollView func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageView } // Nếu đang zoom thì call closure disable scrolling collectionView func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) { let isOriginalSize = scrollView.zoomScale == scrollView.minimumZoomScale scrollViewDidZoomed(isOriginalSize) } // Centering imageView func scrollViewDidZoom(_ scrollView: UIScrollView) { updateImageViewConstraints() } }
Trong SlideShowViewController, thêm một mảng String lưu tên các ảnh sẽ hiển thị.
class SlideShowViewController: UIViewController { @IBOutlet fileprivate weak var slideShowCollectionView: UICollectionView! fileprivate let photos = [ "photo1", "photo2", "photo3", "photo4", "photo5" ] override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) UIApplication.shared.isStatusBarHidden = true } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) UIApplication.shared.isStatusBarHidden = false } @IBAction private func closeButtonTapped(_ sender: Any) { dismiss(animated: true, completion: nil) } }
Màn hình slide show, chúng ta sẽ ẩn status bar. Vì vậy trong Info.plist, hãy thêm property View controller-based status bar appearance với value NO.
Cuối cùng, implement các function cần thiết của 2 protocol UICollectionViewDataSource và UICollectionViewDelegateFlowLayout.
// MARK: - UICollectionViewDataSource extension SlideShowViewController: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return photos.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as? PhotoCollectionViewCell else { return UICollectionViewCell() } // Set photo name cho cell cell.setPhoto(photos[indexPath.row]) // Implement closure cell.scrollViewDidZoomed = { isOriginalSize in collectionView.isScrollEnabled = !isOriginalSize } return cell } } // MARK: - UICollectionViewDelegateFlowLayout extension SlideShowViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // Mỗi cell sẽ có kích thước full màn hình return view.frame.size } }
Kết quả, chúng ta được slide show ảnh như này.
Link final project: https://github.com/oNguyenXuanThanh/StudyReport082018