简体   繁体   English

Swift CollectionView可重用单元注册

[英]Swift CollectionView Reusable Cells Registering

I have a Problem with a CollectionView inside a UIViewcontroller . 我在UIViewcontroller了CollectionView问题。 I get my data from a JSON and in special conditions the cells don't seem to be reused properly, and I think there is something wrong with the way I've setup my Collectionview. 我从JSON获取数据,在特殊条件下,单元格似乎没有被正确重用,我认为我设置Collectionview的方式有问题。

A overview: 概述:

My MyCollectionViewCell.swift : 我的MyCollectionViewCell.swift

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var bottomLabel: UILabel!
    @IBOutlet weak var topLabel: UILabel!

}

As you can see I have two labels in my Cell. 如你所见,我的Cell中有两个标签。 And Parts of my Viewcontroller: 我的Viewcontroller的部分内容:

import UIKit

private let reuseIdentifier = "colcel"

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    override func viewDidLoad() {

        super.viewDidLoad()

        // Register cell classes
        //collectionView.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)

        //SOME JSON PARSING HAPPENS HERE

        collectionView.delegate = self
        collectionView.dataSource = self
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let colcel = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyCollectionViewCell

        colcel.contentView.layer.cornerRadius = 5.0
        colcel.layer.shadowColor = UIColor.darkGray.cgColor
        colcel.layer.shadowOffset = CGSize(width: 12, height: 4.0)
        colcel.layer.shadowRadius = 12.0
        colcel.layer.masksToBounds = false

        return colcel
    }
}

Now when I try to use for Example: 现在,当我尝试使用示例时:

colcel.topLabel.text = "someText"

I get: 我明白了:

fatal error: unexpectedly found nil while unwrapping an Optional value 致命错误:在展开Optional值时意外发现nil

When I remove the collectionview.register in the viewDidLoad() it works. 当我删除viewDidLoad()中的collectionview.register ,它可以正常工作。 Now is the question is my register action not neccesary or is it just wrong? 现在的问题是我的register行动不是必要的,还是错的?

//edit. //编辑。

My Cell REordering: 我的细胞重新排序:

In the viewDidLoad() is this: viewDidLoad()是这样的:

//Long Pressure for reordering
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(ViewController.handleLongGesture))
self.collectionView.addGestureRecognizer(longPressGesture)

This is the corresponding function: 这是相应的功能:

func handleLongGesture(gesture: UILongPressGestureRecognizer) {

    switch(gesture.state) {

    case UIGestureRecognizerState.began:
        guard let selectedIndexPath = self.collectionView.indexPathForItem(at: gesture.location(in: self.collectionView)) else {
            break
        }
        collectionView.beginInteractiveMovementForItem(at: selectedIndexPath)
    case UIGestureRecognizerState.changed:
        collectionView.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))
    case UIGestureRecognizerState.ended:
        collectionView.endInteractiveMovement()
    default:
        collectionView.cancelInteractiveMovement()
    }
}

and I have this function: 我有这个功能:

func collectionView(_ collectionView: UICollectionView,
                    moveItemAt sourceIndexPath: IndexPath,
                    to destinationIndexPath: IndexPath)
{
    // Update data model to reflect the change
    let temp = devArray[sourceIndexPath.row]
    devArray[sourceIndexPath.row] = devArray[destinationIndexPath.row]
    devArray[destinationIndexPath.row] = temp
}

when I run 我跑的时候

self.collectionView.reloadData()

sometimes the positions jump 有时候位置跳跃

If you have designed your storyboard with a prototype cell with the appropriate base class, you should not also register the class. 如果您使用具有相应基类的原型单元设计了故事板,则不应该register该类。 The storyboard prototype cell does all of that for you. 故事板原型单元为您完成所有这些。

The only time you manually register a class is when you are creating the cell programmatically. 您手动注册类的唯一时间是以编程方式创建单元格。 In that case, you should remove the prototype cell, but your custom class has to create the subviews itself and hook up the outlets (no longer @IBOutlet references) programmatically. 在这种情况下,您应该删除原型单元格,但您的自定义类必须自己创建子视图并以编程方式连接出口(不再是@IBOutlet引用)。

In terms of why you'd use prototype cells vs. programmatically creating the cells, it's just much easier to use prototype cells. 就您使用原型单元格而不是以编程方式创建单元格的原因而言,使用原型单元格要容易得多。 You have to write less code. 你必须编写更少的代码。 If you use cell prototypes, storyboards do all of this quite gracefully, so I see no benefit in going old-school and registering the class and programmatically creating the cells manually. 如果您使用单元格原型,故事板可以非常优雅地完成所有这些操作,因此我认为在上学和注册课程并以编程方式手动创建单元格没有任何好处。 It's just how we used to do it before we had prototype cells. 这就是我们在制作原型单元之前的习惯。 But using storyboard vs programmatically created cells shouldn't affect the cell reuse logic. 但是使用storyboard与以编程方式创建的单元格不应该影响单元重用逻辑。

You said: 你说:

... in special conditions the cells don't seem to be reused properly. ...在特殊情况下,细胞似乎没有被正确使用。

You should show us in what case the cells aren't reused. 您应该告诉我们在什么情况下不重复使用单元格。 It's worth noting that when scrolling extremely quickly, cells aren't reused immediately after they scroll out of view. 值得注意的是,当滚动速度非常快时,单元格在滚出视图后不会立即重复使用。 There's a little bit of lag before they're reused. 在重复使用之前有一点滞后。 If that's the scenario you're seeing that behavior, then, yes, I'm not surprised by that behavior. 如果那是你看到那种行为的情景,那么,是的,我对这种行为并不感到惊讶。 If that's not where you're seeing it not successfully dequeue/reuse cells, then share details regarding when and where you're seeing this behavior. 如果您没有看到它未成功出列/重复使用单元格,则分享有关您何时何地看到此行为的详细信息。


Regarding your separate reordering problem, the collectionView(_:moveItemAt:to:) is swapping the source and the destination. 关于单独的重新排序问题, collectionView(_:moveItemAt:to:)正在交换源和目标。 But what you want is to remove and insert : 但你想要的是removeinsert

override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    let value = devArray.remove(at: sourceIndexPath.item)
    devArray.insert(value, at: destinationIndexPath.item)
}

Because you're swapping, the one cell in question looks fine (so everything looks OK when you finish your drag), but all of the other cells in-between will be wrong. 因为你正在交换,所以一个单元格看起来很好(所以当你完成拖动时一切看起来都很好),但中间的所有其他单元格都是错误的。 And you won't see that until you reload the collection view and/or scroll away and then back. 在重新加载集合视图和/或滚动然后返回之前,您不会看到它。 By doing remove and insert , instead, the model should stay in sync. 相反,通过removeinsert ,模型应该保持同步。

请检查UICollectionViewCell属性上的Custom Class,确保值为MyCollectionViewCell - > ScreenShot

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

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