SwipUP 上的 collectionView 动画?

collectionView Animation on SwipUP?

我想根据内容偏移为滑动时的 collectionView 制作动画。它就像一个页面控制器,但只显示一次滑动。我附上了视频,因为我知道解释不好。

Link

您可以从那里下载视频。

有多种方法可以满足您的需求,这里是一种方法:

我正在设置 UIImageView 以及固定到主视图的前导、尾随、顶部和底部锚点的叠加层 UIView

我的目标是像您的示例一样向上滑动集合视图,然后根据在集合视图中点击的单元格更改覆盖视图的颜色。

这里有一些变量和初始设置:

class SwipeCollectionView: UIViewController
{
    private var collectionView: UICollectionView!
    
    private let imageView = UIImageView()
    
    private let overlayView = UIView()
    
    // Collection view data source
    private let colors: [UIColor] = [.red,
                                     .systemBlue,
                                     .orange,
                                     .systemTeal,
                                     .purple,
                                     .systemYellow]
    
    // Store the collection view's bottom anchor which is used
    // to animate the collection view
    private var cvBottomAnchor: NSLayoutConstraint?
    
    // Use this flag to disable swipe actions when carousel is showing
    private var isCarouselShowing = false

    // Use this to check if we are swiping up
    private var previousSwipeLocation: CGPoint?
    
    // Random width and height, change as you wish
    private let cellWidth: CGFloat = 100
    private let collectionViewHeight: CGFloat = 185
    
    private let reuseIdentifier = "cell"
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        configureNavigationBar()
        configureOverlayView()
        configureCollectionView()
    }
    
    private func configureNavigationBar()
    {
        title = "Swipe CV"
        
        let appearance = UINavigationBarAppearance()

        // Color of the nav bar background
        appearance.backgroundColor = .white // primary black for you

        navigationController?.navigationBar.standardAppearance = appearance
        navigationController?.navigationBar.scrollEdgeAppearance = appearance
    }

现在完成一些基本设置后,下面是图像和叠加视图的设置方式。这里没什么特别的,但要注意添加到叠加视图的手势识别器

private func configureOverlayView()
{
    imageView.image = UIImage(named: "dog")
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFill
    
    overlayView.backgroundColor = colors.first!.withAlphaComponent(0.5)
    overlayView.translatesAutoresizingMaskIntoConstraints = false
    
    view.addSubview(imageView)
    view.addSubview(overlayView)
    
    // Auto layout pinning the image view and overlay view
    // to the main container view
    view.addConstraints([
    
        imageView.leadingAnchor
            .constraint(equalTo: view.leadingAnchor),
        imageView.topAnchor
            .constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        imageView.trailingAnchor
            .constraint(equalTo: view.trailingAnchor),
        imageView.bottomAnchor
            .constraint(equalTo: view.bottomAnchor),
        
        overlayView.leadingAnchor
            .constraint(equalTo: view.leadingAnchor),
        overlayView.topAnchor
            .constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
        overlayView.trailingAnchor
            .constraint(equalTo: view.trailingAnchor),
        overlayView.bottomAnchor
            .constraint(equalTo: view.bottomAnchor)
    
    ])
    
    // We will observe a swipe gesture to check if it is a swipe
    // upwards and then react accordingly
    let swipeGesture = UIPanGestureRecognizer(target: self,
                                              action: #selector(didSwipe(_:)))
    overlayView.addGestureRecognizer(swipeGesture)
}

现在一旦完成,我们需要创建一个水平滚动的 uicollectionview,它位于屏幕外,当我们向上滑动时可以在其中动画,这是完成的方法

private func configureCollectionView()
{
    collectionView = UICollectionView(frame: .zero,
                                      collectionViewLayout: createLayout())
    
    collectionView.backgroundColor = .clear
    
    collectionView.register(UICollectionViewCell.self,
                            forCellWithReuseIdentifier: reuseIdentifier)
    
    collectionView.translatesAutoresizingMaskIntoConstraints = false
    
    collectionView.showsHorizontalScrollIndicator = false
    
    // Add some padding for the content on the left
    collectionView.contentInset = UIEdgeInsets(top: 0,
                                               left: 15,
                                               bottom: 0,
                                               right: 0)
    
    collectionView.dataSource = self
    collectionView.delegate = self
    
    overlayView.addSubview(collectionView)
    
    // Collection View should start below the screen
    // We need to persist with this constraint so we can change it later
    
    let bottomAnchor = overlayView.safeAreaLayoutGuide.bottomAnchor
    
    cvBottomAnchor
        = collectionView.bottomAnchor.constraint(equalTo: bottomAnchor,
                                                 constant: collectionViewHeight)
    
    // Collection View starts as hidden and will be animated in swipe up
    collectionView.alpha = 0.0
    
    // Add collection view constraints
    overlayView.addConstraints([
    
        collectionView.leadingAnchor.constraint(equalTo: overlayView.leadingAnchor),
        cvBottomAnchor!,
        collectionView.trailingAnchor.constraint(equalTo: overlayView.trailingAnchor),
        collectionView.heightAnchor.constraint(equalToConstant: collectionViewHeight)
    
    ])
}

private func createLayout() -> UICollectionViewFlowLayout
{
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    
    layout.itemSize = CGSize(width: cellWidth, height: collectionViewHeight)
    layout.minimumInteritemSpacing = 20
    
    return layout
}

到目前为止的代码应该是这样的:

您仍然看不到集合视图,为此,执行平移手势的 didSwipe 动作

@objc
private func didSwipe(_ gesture: UIGestureRecognizer)
{
    if !isCarouselShowing
    {
        let currentSwipeLocation = gesture.location(in: view)
        
        if gesture.state == .began
        {
            // record the swipe location when we start the pan gesture
            previousSwipeLocation = currentSwipeLocation
        }
        
        // On swipe continuation, verify the swipe is in the upward direction
        if gesture.state == .changed,
           let previousSwipeLocation = previousSwipeLocation,
           currentSwipeLocation.y < previousSwipeLocation.y
        {
            isCarouselShowing = true
            revealCollectionView()
        }
    }
}

// Animate the y position of the collection view and the alpha
private func revealCollectionView()
{
    // We need to set the top constraint (y position)
    // to be somewhere above the screen plus some padding
    cvBottomAnchor?.constant = 0 - 75
    
    UIView.animate(withDuration: 0.25) { [weak self] in
        
        // animate change in constraints
        self?.overlayView.layoutIfNeeded()
        
        // reveal the collection view
        self?.collectionView.alpha = 1.0
        
    } completion: { (finished) in
        
        // do something
    }
}

最后,为了完整起见,这里是集合视图数据源和委托:

extension SwipeCollectionView: UICollectionViewDataSource
{
    func collectionView(_ collectionView: UICollectionView,
                        numberOfItemsInSection section: Int) -> Int
    {
        return colors.count
    }
    
    func collectionView(_ collectionView: UICollectionView,
                        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
        let cell
            = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
                                                      for: indexPath)
        
        cell.layer.cornerRadius = 20
        cell.clipsToBounds = true
        cell.contentView.backgroundColor = colors[indexPath.item]
        
        return cell
    }
}

extension SwipeCollectionView: UICollectionViewDelegate
{
    func collectionView(_ collectionView: UICollectionView,
                        didSelectItemAt indexPath: IndexPath)
    {
        overlayView.backgroundColor
            = colors[indexPath.item].withAlphaComponent(0.5)
    }
}

现在 运行 当您向上滑动时,这应该会给您这样的体验:

我相信这应该足以让您入门

更新

示例的完整源代码可在 gist here