繁体   English   中英

使用自动约束 Swift 为 UICollectionView 设置动画

[英]Animating UICollectionView With Auto Constraints Swift

我在inputAccessoryView UICollectionView用于在创建帖子时选择图像(类似于 Twitter)。

当用户开始打字时,我想使用UIView动画功能为UICollectionView设置动画。

首选结果

推特收藏视图

代码

func animateCollectionView() {
    UIView.animate(withDuration: 1, delay: 0, options: .showHideTransitionViews) {
        self.collectionView.transform = .init(scaleX: 0, y: 100)
    } completion: { finished in
        if finished {
            print("ANIMATION COMPLETED")
        }
    }
}

有了这个, UICollectionView立即被删除,控制台在 1 秒后打印(如预期)。 但是,动画没有发生。

约束条件

NSLayoutConstraint.activate([
            uploadVoiceNoteButton.heightAnchor.constraint(equalToConstant: 48),
            uploadMediaButton.heightAnchor.constraint(equalToConstant: 48),
            uploadPollButton.heightAnchor.constraint(equalToConstant: 48),
            characterCountView.heightAnchor.constraint(equalToConstant: 48),
            characterCountView.widthAnchor.constraint(equalToConstant: 18),
        
        hStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
        hStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
        hStackView.bottomAnchor.constraint(equalTo: bottomAnchor),
        
        separator.heightAnchor.constraint(equalToConstant: Height.separator),
        separator.leadingAnchor.constraint(equalTo: leadingAnchor),
        separator.trailingAnchor.constraint(equalTo: trailingAnchor),
        separator.topAnchor.constraint(equalTo: hStackView.topAnchor),
        
        replyAllowanceButton.heightAnchor.constraint(equalToConstant: 51),
        replyAllowanceButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
        replyAllowanceButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
        replyAllowanceButton.bottomAnchor.constraint(equalTo: separator.topAnchor),
        
        collectionViewSeparator.bottomAnchor.constraint(equalTo: replyAllowanceButton.topAnchor),
        collectionViewSeparator.leadingAnchor.constraint(equalTo: leadingAnchor),
        collectionViewSeparator.trailingAnchor.constraint(equalTo: trailingAnchor),
        collectionViewSeparator.heightAnchor.constraint(equalToConstant: Height.separator),
        
        collectionView.topAnchor.constraint(equalTo: topAnchor),
        collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
        collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
        collectionView.bottomAnchor.constraint(equalTo: collectionViewSeparator.topAnchor, constant: -8),
    ])

我建议将集合视图和分隔符视图嵌入到“容器” UIView中。

给集合视图前导/尾随(到容器视图)和高度约束,但没有底部约束(也没有顶部约束)。

给分隔符视图 Leading/Trailing(给容器视图),Top 给集合视图 Bottom,和 Height 约束,但没有 Bottom 约束。

给容器视图一个高度约束,以便集合视图和分隔视图(可能还有一点间距)适合。

添加“可见”和“隐藏”约束作为 var 属性:

var cvVisibleConstraint: NSLayoutConstraint!
var cvHiddenConstraint: NSLayoutConstraint!

然后,当我们设置所有其他约束时,像这样创建这两个约束:

    // collectionView TOP constrained to TOP of container when visible
    cvVisibleConstraint = collectionView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 8.0)

    // collectionView TOP constrained to BOTTOM of container when hidden
    cvHiddenConstraint = collectionView.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 8.0)

要显示/隐藏集合视图(和分隔符,因为它受限于集合视图):

containerView.clipsToBounds = true

和:

cvVisibleConstraint.isActive.toggle()
cvHiddenConstraint.isActive = !cvVisibleConstraint.isActive
UIView.animate(withDuration: 0.5, animations: {
    self.view.layoutIfNeeded()
})

这是一个例子......我在主视图中添加一个视图来模拟输入附件视图,但方法是相同的:

class ShowHideVC: UIViewController {
    
    var collectionView: UICollectionView!
    let collectionViewSeparator = UIView()
    let containerView = UIView()
    let myInputAccessoryView = UIView()
    
    var cvVisibleConstraint: NSLayoutConstraint!
    var cvHiddenConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let fl = UICollectionViewFlowLayout()
        fl.scrollDirection = .horizontal
        fl.itemSize = CGSize(width: 72.0, height: 72.0)
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: fl)
        
        [myInputAccessoryView, containerView, collectionViewSeparator, collectionView].forEach { v in
            v?.translatesAutoresizingMaskIntoConstraints = false
        }
        
        containerView.addSubview(collectionView)
        containerView.addSubview(collectionViewSeparator)
        myInputAccessoryView.addSubview(containerView)
        
        view.addSubview(myInputAccessoryView)
        
        let g = view.safeAreaLayoutGuide
        
        // collectionView TOP constrained to TOP of container when visible
        cvVisibleConstraint = collectionView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 8.0)

        // collectionView TOP constrained to BOTTOM of container when hidden
        cvHiddenConstraint = collectionView.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 8.0)

        // setting priorities to (999) avoids auto-layout complaints when toggling active
        cvVisibleConstraint.priority = .required - 1
        cvHiddenConstraint.priority = .required - 1

        NSLayoutConstraint.activate([
            
            myInputAccessoryView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            myInputAccessoryView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            myInputAccessoryView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            
            myInputAccessoryView.heightAnchor.constraint(equalToConstant: 200.0),
            
            containerView.topAnchor.constraint(equalTo: myInputAccessoryView.topAnchor, constant: 8.0),
            containerView.leadingAnchor.constraint(equalTo: myInputAccessoryView.leadingAnchor, constant: 8.0),
            containerView.trailingAnchor.constraint(equalTo: myInputAccessoryView.trailingAnchor, constant: -8.0),
            
            containerView.heightAnchor.constraint(equalToConstant: 100.0),
            
            // start with collection view showing
            cvVisibleConstraint,
            
            collectionView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8.0),
            collectionView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8.0),

            collectionView.heightAnchor.constraint(equalToConstant: 78.0),
            
            collectionViewSeparator.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 8.0),
            collectionViewSeparator.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8.0),
            collectionViewSeparator.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8.0),
            
            collectionViewSeparator.heightAnchor.constraint(equalToConstant: 1.0),

            // no bottom constraints for collectionView or collectionViewSeparator
            
        ])
        
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "c")
        collectionView.dataSource = self
        collectionView.delegate = self
        
        // colors so we can see framing
        collectionView.backgroundColor = .systemGreen
        collectionViewSeparator.backgroundColor = .red
        containerView.backgroundColor = .yellow
        myInputAccessoryView.backgroundColor = .systemYellow
        
        // comment / un-comment the next line to see what's really going on
        containerView.clipsToBounds = true
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        cvVisibleConstraint.isActive.toggle()
        cvHiddenConstraint.isActive = !cvVisibleConstraint.isActive
        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        })
    }
}

extension ShowHideVC: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let c = collectionView.dequeueReusableCell(withReuseIdentifier: "c", for: indexPath)
        c.contentView.backgroundColor = .green
        c.contentView.layer.cornerRadius = 8
        return c
    }
}

它将在屏幕上的任何点击(动画)之间切换显示和隐藏,如下所示:

在此处输入图像描述 在此处输入图像描述

在此处输入图像描述 在此处输入图像描述

注意viewDidLoad()中的最后一行:

// comment / un-comment the next line to see what's really going on
containerView.clipsToBounds = true

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM