(Swift) Swipe left and right to zoom the view (large in the middle and small on both sides)

created at 11-14-2021 views: 33

1) Usage scenario

  • Mostly used for photo display, slide left and right to show zoom effect (large in the middle and small on both sides);
  • Encapsulated as a UIView object, flexible to use;
  • The effect is as follows;

example

2) How to use

5 lines of code, it can be presented;
Silky as if using UICollectionView;

let zoomV = CCZoomCardView()
view.addSubview(zoomV)
zoomV.delegate = self
zoomV.register(CCTestCell.self, forCellWithReuseIdentifier: classString())
zoomV.snp.remakeConstraints { (make) in
  make.center.equalToSuperview()
  make.size.equalTo(CGSize(width: kScreenWidth(), height: (kScreenHeight().d * 0.6).i))
}

Register a custom cell

zoomV.register(CCTestCell.self, forCellWithReuseIdentifier: classString())

Follow the CCZoomCardViewDelegate protocol and implement the protocol method

    // MARK: - CCZoomCardViewDelegate
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        20
    }

    // MARK: - CCZoomCardViewDelegate
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        collectionView.dequeueReusableCell(withReuseIdentifier: classString(), for: indexPath) as! CCTestCell
    }

    // MARK: - CCZoomCardViewDelegate
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print(indexPath)
    }

3) source code sharing

//
//  CCZoomCardView.swift
//  HelloSwift
//
//  Created by well on 2021/9/26.
//

import UIKit

protocol CCZoomCardViewDelegate: NSObjectProtocol {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
}

// Custom flowLayout
class CCZoomCardCollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { true }

    override func prepare() {
        super.prepare()
        let margin = ((collectionView!.frame.width) - itemSize.width) / 2
        collectionView!.contentInset = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let superArray = super.layoutAttributesForElements(in: rect)
        let tempArray = NSArray(array: superArray!, copyItems: true) as! [UICollectionViewLayoutAttributes]
        let centerX = collectionView!.contentOffset.x + collectionView!.frame.size.width * 0.5
        for item  in tempArray.enumerated() {
            let distance = abs(item.element.center.x - centerX)
            let scale = 1 - distance / (collectionView?.frame.width)!
            item.element.transform = CGAffineTransform(scaleX: scale, y: scale)
        }
        return tempArray
    }

    override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
        var contentOffset = proposedContentOffset
        let rect = CGRect(x: contentOffset.x, y: 0, width: collectionView!.frame.size.width, height: collectionView!.frame.size.height)
        let arr = super.layoutAttributesForElements(in: rect)
        let centerX: CGFloat = contentOffset.x + collectionView!.frame.size.width * 0.5
        var minDistance = CGFloat(MAXFLOAT)
        for item  in arr!.enumerated() {
            let distance = item.element.center.x - centerX
            if (abs(distance) < abs(minDistance)) {
                minDistance = distance
            }
        }
        contentOffset.x += minDistance
        return contentOffset
    }
}

class CCZoomCardView: UIView, UICollectionViewDelegate, UICollectionViewDataSource {

    /// 代理对象
    weak var delegate: CCZoomCardViewDelegate?

    /// Lazy loading flowLayout
    private lazy var flowLayout: CCZoomCardCollectionViewFlowLayout = {
        let layout = CCZoomCardCollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        return layout
    }()

    /// Lazy loading collectionView
    private lazy var collectionView: UICollectionView = {
        let c = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
        c.delegate = self
        c.dataSource = self
        c.showsHorizontalScrollIndicator = false
        c.contentInsetAdjustmentBehavior = .never
        return c
    }()

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // MARK:-Deinitializer
    deinit { print("CCZoomCardView deinit!") }

    // MARK:-Initializer
    override init(frame: CGRect) {
        super.init(frame: .zero)
        self.setUI()
    }

    override func layoutSubviews() {
        flowLayout.itemSize = CGSize(width: self.frame.width * 0.6, height: self.frame.height * 0.6)
    }

    func setUI() {
        self.addSubview(collectionView)
        collectionView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }

    // MARK: - UICollectionViewDelegate
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        (delegate?.collectionView(collectionView, numberOfItemsInSection: section))!
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        (delegate?.collectionView(collectionView, cellForItemAt: indexPath))!
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        delegate?.collectionView(collectionView, didSelectItemAt: indexPath)
    }

    // MARK:-Register a custom cell
    func register(_ cellClass: AnyClass?, forCellWithReuseIdentifier identifier: String) {
        collectionView.register(cellClass, forCellWithReuseIdentifier: identifier)
    }
}
created at:11-14-2021
edited at: 11-14-2021: