如何使用自定义 UIViews(以及内部的转换)重新加载自定义 UICollectionViewCell

Posted

技术标签:

【中文标题】如何使用自定义 UIViews(以及内部的转换)重新加载自定义 UICollectionViewCell【英文标题】:How to reload custom UICollectionViewCell`s with custom UIViews (and transitions inside) 【发布时间】:2020-09-24 09:21:20 【问题描述】:

大家好,

我正在根据 indexPath 行在我的自定义单元格中重新加载数据方面寻找一些提示。

上下文:

我有一个教程幻灯片,我正在使用UICollectionView。在这个视图中,我插入了自定义 UICollectionViewCells,为每个 indexPath.row 不同的自定义一个(所以我为 UICollectionView 注册了多个 nib)。

在基于 indexPath.row 的委托方法 cellForItemAt indexPath 中,我将我想要的特定自定义单元格出列

教程幻灯片包含按钮,您可以使用这些按钮在特定单元格之间导航(顺便说一下,单元格占据了大部分用户屏幕),因此您可以像下一步或返回一样导航。

其自定义类中的每个单元格都定义了一些转换。因此,例如单元格 1 以一些自定义元素开始,然后在第二个左右之后它转换到另一组元素。所以我正在创造类似动画的东西。这些转换是通过DispatchQueue.main.asyncAfter 执行的,所以我让用户阅读我想要的第一个屏幕,然后是第二个。然后用户单击下一步按钮并转到另一个indexPath.row,有时会在下一个“屏幕”内进行另一个转换

所以我的意图是当用户例如通过单击下一步/返回在单元格之间导航(indexPath.row/s)时具有“清晰”的默认视图,所以当他从 Screen2 转到 Screen1 时,我希望他看到Screen1 从头开始​​并再次查看转换。现在它结束于我转换到的最后一个屏幕。

我的实际问题:

那么有什么方法可以用当前设计刷新单元格,或者我应该改变我构建集合视图的方式吗?

请参阅下面的一些示例代码 sn-ps。

1. VC 与我的 UICollectionView

class IncomingInstructionsVC: UIViewController 

@IBOutlet weak var btnBack: UIButton!
@IBOutlet weak var btnNext: UIButton!
@IBOutlet weak var collectionView: UICollectionView!


override func viewDidLoad() 
    super.viewDidLoad()
    collectionView.register(Screen1.nib, forCellWithReuseIdentifier: "Screen1ID")
    collectionView.register(Screen2.nib, forCellWithReuseIdentifier: "Screen2ID")
    collectionView.register(Screen3.nib, forCellWithReuseIdentifier: "Screen3ID")
    collectionView.register(Screen4.nib, forCellWithReuseIdentifier: "Screen4ID")
    collectionView.register(Screen5.nib, forCellWithReuseIdentifier: "Screen5ID")
    collectionView.register(Screen6.nib, forCellWithReuseIdentifier: "Screen6ID")
    collectionView.dataSource = self
    collectionView.delegate = self
    collectionView.isPagingEnabled = false


2。用于 UICollectionViewCell/s 之间导航的 IBActions

@IBAction func btnNextTapped(_ sender: UIButton) 
    let visibleItems: NSArray = self.collectionView.indexPathsForVisibleItems as NSArray
    
    var minItem: NSIndexPath = visibleItems.object(at: 0) as! NSIndexPath
    for itr in visibleItems 
        if minItem.row > (itr as AnyObject).row 
            minItem = itr as! NSIndexPath
        
    
    let nextItem = IndexPath(row: minItem.row + 1, section: 0)
    self.collectionView.scrollToItem(at: nextItem as IndexPath, at: .left, animated: false)


@IBAction func btnBackTapped(_ sender: UIButton) 
    let visibleItems: NSArray = self.collectionView.indexPathsForVisibleItems as NSArray
    
    var minItem: NSIndexPath = visibleItems.object(at: 0) as! NSIndexPath
    for itr in visibleItems 
        
        if minItem.row > (itr as AnyObject).row 
            minItem = itr as! NSIndexPath
        
    
    let nextItem = IndexPath(row: minItem.row - 1, section: 0)
    self.collectionView.scrollToItem(at: nextItem as IndexPath, at: .left, animated: false)

3.委托方法 cellForItemAt indexPath:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    
    var cell = UICollectionViewCell()
    self.pageControl.currentPage = indexPath.row
    
    switch indexPath.row 
    case 0:
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Screen1ID", for: indexPath) as! Screen1
    case 1:
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Screen2ID", for: indexPath) as! Screen2
    case 2:
        cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Screen3ID", for: indexPath) as! Screen3
.
.
.
continues to the end of my tutorial
.
.
.
    
    return cell


4.自定义单元类定义与 DispatchQueue.main.asyncAfter 逻辑

.
.
.
Some IBOutlets here....
.
.
.

override func awakeFromNib() 
        super.awakeFromNib()
        commonInit()
    
    
    func commonInit() 
        greyBackground.layer.cornerRadius = 10
        transition1.layer.cornerRadius = 10
        transition2.layer.cornerRadius = 10
        
        self.nameIncomingLabel.text = NSLocalizedString("name_inc_head", comment: "")
        self.mobileLabel.text = NSLocalizedString("mobile", comment: "")
        self.declineImageView.image = UIImage(named: "Reject")
        self.declineLabel.text = NSLocalizedString("Decline", comment: "")
        
        self.acceptImageView.image = UIImage(named: "Accept")
        self.acceptLabel.text = NSLocalizedString("accept", comment: "")
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)  [self] in
            //transition to "Accept Call" command
            UIView.transition(with: transition1, duration: 1, options: .transitionCrossDissolve, animations: 
                transition1.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.9)
                
                transition1AcceptImage.image = UIImage(named: "Accept")
                transition1Label.font = UIFont.systemFont(ofSize: 21, weight: .semibold)
                transition1Label.text = NSLocalizedString("answer_incoming_call", comment: "")
                
                //transition to calling screen with icons
                DispatchQueue.main.asyncAfter(deadline: .now() + 1.5)  [self] in
                    UIView.transition(with: transition2, duration: 0.5, options: .transitionCrossDissolve, animations: 
                        transition2.backgroundColor = #colorLiteral(red: 0.3019607843, green: 0.3019607843, blue: 0.3019607843, alpha: 1)
                        nameIncomingLabelTransition2.text = NSLocalizedString("name_inc_head", comment: "")


....it is continuing with the closing curly braces down below...

【问题讨论】:

【参考方案1】:

dequeueing 可重用单元格的目的是避免多次创建单元格,这些单元格可以更快地被容器视图(如表格视图或集合视图)重用。容器视图缓存了许多离开屏幕的单元格,因此一旦该单元格再次可见,您就可以返回该单元格。 由于您的动画是在 commonInit 中实现的 - 仅由 awakeFromNib 调用 - 您只能看到它们一次,因为视图只加载到内存中一次。

您需要在单元格出列后手动调用commonInit,而不要通过awakeFromNib 调用它。 或者更好:将 only once 从动画/内容初始化部分中分离出来,然后从 awakeFromNib 调用第一个,后者在视图出列后调用。

这更好,因为 awakeFromNib 甚至在视图可见之前就被调用了,因此您甚至不知道它何时显示。

【讨论】:

您好@Andreas Oetjen,感谢您的回复。请注意我是如何根据对您的提示的理解更新代码的。从commonInit()我拿出了第一个屏幕初始化代码,比如标签和字符串。然后从带有出队的委托方法中,我用动画调用了新方法(在自定义单元类中声明),但结果是一样的。当我回到 indexPath.row 时,它仍然存在于我的动画逻辑的最后一部分。是否可以从您的角度分享代码 sn-p 您的意思?感谢您的努力。

以上是关于如何使用自定义 UIViews(以及内部的转换)重新加载自定义 UICollectionViewCell的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 4 中从 UIViews 加载 nib?

在 Interface Builder 中,如何将 UIViews 添加到属于我创建的自定义视图的子视图?

如何将 UIViews 添加到我的 contentView (AwakeFromNib)

UIViews 到垂直 3D 堆栈

如何与内部 svn 存储库共享自定义 Grails 插件?

ansible中过滤器的介绍以及如何自定义过滤器