实现collectionViewCell的移动(长按或者直接拖拽)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现collectionViewCell的移动(长按或者直接拖拽)相关的知识,希望对你有一定的参考价值。

参考技术A 最近在实现类似网易新闻的首页滑块的编辑效果: 长按后进入编辑界面, 然后可以通过拖拽实现cell的移动, 研究后发现两种实现方式: 第一种是直接利用系统提供的UICollectionView API实现移动, 不过只能在ios9上面使用. 所以这里就介绍另外一种方式.

源码效果示例:

2 在selector中处理手势的响应

a. 记录下当前的indexPath以便于在手指移动的过程中进入.Changed状态的时候使用
b. 通过这个indexPath获取到对应的cell
c. 获取到这个cell截图
d. 并且设置截图的初始位置
e. 隐藏当前的cell
f. 将截图添加到collectionView中

a. 如果在began状态中没有获取到截图直接返回
b. 设置截图的位置, 以达到和手指同步移动
c. 如果新获取到的indexPath有效并且和原来的不相同
d. 移动cell, 更新dataSource
e. 设置新的cell的属性
f. 更新当前的indexPath

a. 获取到当前移动完成的cell
b. 使用动画移除截图并且设置当前的移动完成的cell的属性

如何实现可以显示图像或作为输入属性提供的自定义 UIView 的 CollectionViewCell?

【中文标题】如何实现可以显示图像或作为输入属性提供的自定义 UIView 的 CollectionViewCell?【英文标题】:How to implement a CollectionViewCell that can either display an image or a custom UIView provided as input property? 【发布时间】:2017-01-18 20:36:50 【问题描述】:

我有一个collectionView 单元格,它应该显示一个图像或一个生成为自定义UIView 的图标(比如说IconView)。 目前,我通过将UIImageViewIconView 作为子视图添加到容器视图来实现这一点。

当提供图像时,UIImageView 的图像属性会简单地更新。当提供新的IconView 时,它当前总是作为子视图添加到容器视图中。因此,在添加之前,首先检查IconView是否已经添加,如果已经添加,则删除。

虽然这个实现有效,但它不是很优雅,而且似乎效率不高,因为当行数增加时会导致滚动问题。

是否有更好(更有效)的方法来为单个 CollectionViewCell 实现这一点?

class CustomCell: UICollectionViewCell 

    internal var image: UIImage? 
        didSet 
            self.imageView.image = image!
        
    

    internal var iconView: IconView? 
        didSet 
            if !(self.iconContainerView.subviews.flatMap $0 as? IconView.isEmpty) 
                self.iconView!.removeFromSuperview()
            
            self.iconView!.translatesAutoresizingMaskIntoConstraints = false
            self.iconContainerView.addSubview(self.iconView!)
            self.image = nil            
        
    

    fileprivate var imageView: UIImageView!
    fileprivate var iconContainerView: UIView!
    fileprivate var layoutConstraints = [NSLayoutConstraint]()

    override init(frame: CGRect) 
        super.init(frame: frame)

        // ContainerView
        self.iconContainerView = UIView()
        self.iconContainerView.translatesAutoresizingMaskIntoConstraints = false
        self.contentView.addSubview(self.iconContainerView)

        // ImageView
        self.imageView = UIImageView()
        self.imageView.translatesAutoresizingMaskIntoConstraints = false
        self.iconContainerView.addSubview(self.imageView)
    

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

    override func layoutSubviews() 
        super.layoutSubviews()

        self.iconContainerView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor).isActive = true
        self.iconContainerView.widthAnchor.constraint(equalToConstant: 60).isActive = true
        self.iconContainerView.heightAnchor.constraint(equalToConstant: 60).isActive = true
        self.iconContainerView.centerYAnchor.constraint(equalTo: self.contentView.centerYAnchor).isActive = true

        // Deactivate non-reusable constraints
        _ = self.layoutConstraints.map  $0.isActive = false 
        self.layoutConstraints = [NSLayoutConstraint]()

        if let iconView = self.iconView 
            self.imageView.isHidden = true
            self.layoutConstraints.append(iconView.centerYAnchor.constraint(equalTo: self.iconContainerView.centerYAnchor))
            self.layoutConstraints.append(iconView.centerXAnchor.constraint(equalTo: self.iconContainerView.centerXAnchor))
            self.layoutConstraints.append(iconView.heightAnchor.constraint(equalToConstant: 40))
            self.layoutConstraints.append(iconView.widthAnchor.constraint(equalToConstant: 40))
         else 
            self.imageView.isHidden = false
            self.iconView?.isHidden = true
            self.layoutConstraints.append(self.imageView.leadingAnchor.constraint(equalTo: self.iconContainerView.leadingAnchor))
            self.layoutConstraints.append(self.imageView.trailingAnchor.constraint(equalTo: self.iconContainerView.trailingAnchor))
            self.layoutConstraints.append(self.imageView.topAnchor.constraint(equalTo: self.iconContainerView.topAnchor))
            self.layoutConstraints.append(self.imageView.bottomAnchor.constraint(equalTo: self.iconContainerView.bottomAnchor))
        
        _ = self.layoutConstraints.map $0.isActive = true
    

【问题讨论】:

你不能使用两个不同的UICollectionViewCells有什么原因吗? 我使用的 collectionView 单元格相当长,图像/图标是唯一的布局差异。我不知道两个 UICollectionView 是否会提高性能,因为可以重用的单元格更少。此外,它需要在每个类和一个公共父类中重复所有约束。不是很有吸引力,但如果这是我会考虑的唯一方式。但是真的不能在单个单元格中显示自定义视图吗? 【参考方案1】:

设置时不要广告和删除 IconView。将两者添加到同一位置并更改 isHidden、alpha 或不透明度或bringSubviewToFront。这对主线程的密集程度要低得多。

【讨论】:

是的,但是每次渲染单元格时都应该显示一个全新的“IconView”。如果仅更新了 IconView 的属性,您的建议将是正确的(就像我已经为 UIImageView 所做的那样,在提供 IconView 时将被设置为隐藏)。理想情况下,IconView 也应该作为属性提供......有什么想法吗?

以上是关于实现collectionViewCell的移动(长按或者直接拖拽)的主要内容,如果未能解决你的问题,请参考以下文章

如何实现可以显示图像或作为输入属性提供的自定义 UIView 的 CollectionViewCell?

为啥我的 collectionViewCell 显示异常行为?

移动端的长按事件的实现

如何更改自定义 CollectionViewCell 的背景颜色?

从 xib 文件移动到 Objective C 中的视图控制器

iOS:长按时在 uicollectionViewcell 上显示带有文本的标签