简体   繁体   English

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

[英]How to reload custom UICollectionViewCell`s with custom UIViews (and transitions inside)

Hello all good people,大家好,大家好

I am looking for some hint in terms of reloading data in my custom cells based on the indexPath row.我正在根据 indexPath 行在我的自定义单元格中重新加载数据方面寻找一些提示。

The context:上下文:

  • I have a tutorial slideshow, for which I am using UICollectionView .我有一个教程幻灯片,我正在使用UICollectionView Into this view I insert custom UICollectionViewCell s, for each indexPath.row different custom one (so I register multiple nibs for UICollectionView ).在这个视图中,我插入自定义UICollectionViewCell s,对于每个indexPath.row不同的自定义一个(所以我为UICollectionView注册了多个笔尖)。

  • Within delegate method cellForItemAt indexPath based on the indexPath.row I dequeue particular custom cell I want在基于cellForItemAt indexPath委托方法cellForItemAt indexPath我出列我想要的特定自定义单元格

  • The tutorial slideshow has buttons with which you can navigate between specific cells (btw cells take most of the user screen), so you can navigate like Next or Back.教程幻灯片有一些按钮,您可以使用这些按钮在特定单元格之间导航(顺便说一下,单元格占据了用户屏幕的大部分),因此您可以像 Next 或 Back 一样导航。

  • Each cell within its own custom class is defined with some transitions.自定义类中的每个单元格都定义了一些转换。 So for example cell number 1 starts with some custom elements then after second or so it transits to another sets of elements.因此,例如,单元格编号 1 以一些自定义元素开头,然后在大约一秒后转换为另一组元素。 So I am creating something like animations.所以我正在创建类似动画的东西。 These transitions are performed via DispatchQueue.main.asyncAfter so I let the user to read the first screen I want, then second.这些转换是通过DispatchQueue.main.asyncAfter执行的,所以我让用户阅读我想要的第一个屏幕,然后是第二个。 Then user clicks the button Next and goes for another indexPath.row with sometimes another transitions within this next "screen"然后用户单击 Next 按钮并转到另一个indexPath.row有时在下一个“屏幕”中进行另一个转换

  • So my intention is to have "clear" default view when the user for example navigates between the cells( indexPath.row /s) by clicking Next/Back, so when he goes from Screen2 to Screen1, I want him to see the Screen1 from beginning and see the transitions again.所以我的目的是当用户例如通过单击 Next/Back 在单元格 ( indexPath.row /s) 之间导航时拥有“清晰”的默认视图,所以当他从 Screen2 转到 Screen1 时,我希望他从开始并再次看到过渡。 Now it ends up at the last screen which I transit to.现在它在我过渡到的最后一个屏幕结束。

My actuall Question:我的实际问题:

So is there any way how to refresh the cell with the current design or should I change the way how I structured my collection view?那么有什么方法可以使用当前设计刷新单元格,还是应该更改我构建集合视图的方式?

Please see some example code snippets below.请参阅下面的一些示例代码片段。

1. VC with my UICollectionView 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. IBActions for navigation between UICollectionViewCell/s 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. Delegate method cellForItemAt indexPath: 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. Custom Cell Class definiton with DispatchQueue.main.asyncAfter logic 4. 自定义 Cell Class 与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...

The intention of dequeueing reusable cells is to avoid the multiple creation of cells which could faster be reused by the container view (like table view or collection view).出列可重用单元格的目的是避免多次创建可以由容器视图(如表视图或集合视图)更快地重用的单元格。 The container view caches a lot of cells that go off-screen, so you get back that cell once it becomes visible again.容器视图缓存了许多离开屏幕的单元格,因此一旦它再次可见,您就可以返回该单元格。 Since your animations are implemented in commonInit - which is only called by awakeFromNib - you only see them once, because the view is loaded only once into memory.由于您的动画是在commonInit中实现的——它只能由awakeFromNib调用——你只能看到它们一次,因为视图只加载到内存中一次。

You need call commonInit manually after a cell has been dequeued, and not call it by awakeFromNib .您需要在单元格出队后手动调用commonInit ,而不是通过awakeFromNib调用它。 Or better: Separate the only once stuff from the animation / content initialization part, and call the first from awakeFromNib , the latter once the view get's dequeued.或者更好:将唯一一次的东西与动画/内容初始化部分分开,并从awakeFromNib调用第一个,一旦视图出列,则调用后者。

This is even better because awakeFromNib is called even before the view get's visible, hence you don't even know when it is being displayed.这甚至更好,因为甚至在视图可见之前就调用了awakeFromNib ,因此您甚至不知道它何时显示。

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

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