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

问题描述

大家好,

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

上下文:

  • 我有一个教学幻灯片,我正在使用UICollectionView。在此视图中,我为每个UICollectionViewCell个不同的自定义对象插入自定义indexPath.row(因此我为UICollectionView注册了多个笔尖)。

  • 在基于indexPath.row的委托方法cellForItemAt indexPath中,我将所需的特定自定义单元出队

  • 本教程的幻灯片显示具有一些按钮,您可以使用这些按钮在特定的单元格之间导航(btw单元格占据了用户屏幕的大部分),因此您可以像“下一步”或“上一步”一样进行导航。

  • 在其自己的自定义类中的每个单元格都经过一些转换定义。因此,例如1号单元格从一些自定义元素开始,然后在大约2秒钟后过渡到另一组元素。因此,我正在创建类似动画的内容。这些转换是通过dispatchQueue.main.asyncAfter执行的,所以我让用户阅读了我想要的第一个屏幕,然后阅读了第二个屏幕。然后,用户单击下一步按钮,然后转到另一个indexPath.row,有时在下一个“屏幕”中还会有另一个过渡

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

我的实际问题:

那么,有什么方法可以用当前设计刷新单元格,还是应该更改构造集合视图的方式?

请在下面查看一些示例代码片段。

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,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,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...

解决方法

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

您需要在单元格出队后手动调用commonInit,而可以通过awakeFromNib进行调用。 或更妙的是:将仅一次内容与动画/内容初始化部分分开,然后从awakeFromNib中调用第一个,而一旦视图退出队列,则调用后者。

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