繁体   English   中英

如果滚动,swift collectionview单元格didSelectItemAtIndexPath显示错误的单元格

[英]swift collectionview cell didSelectItemAtIndexPath shows wrong cell if you scroll

假设您在UICollectionView的单元格(来自图像名称数组)中设​​置了一堆图像视图,并在设置项目时默认设置为alpha 0.5。

然后在didSelectItemAtIndexPath函数中将图像视图的alpha设置为1.0,因此当用户点击时它变为alpha 1。

这在用户点击单元格时有效,但如果用户滚动则不会保留,因为该单元正在某些其他级别上被UI重用。

结果是另一个单元格(滚动时)变为alpha 1.0并且您选择的原始单元格将恢复为之前的alpha 0.5外观。

我知道这一切都是为了在设备上提高效率,但我仍然没有弄清楚如何让它在所选项目持续存在的情况下正常工作。

回答

Apple 确实为可用于更改背景颜色,阴影效果或轮廓等的单元格提供selectedBackgroundView。它们还允许您使用“默认”和“突出显示”状态在单元格内使用图像。

这两种方法都会在选择正确的情况下持续存在。

但是,如果您希望使用属性或不同的元素之一来指示您选择的状态,则必须使用包含对当前所选项的引用的单独数据模型元素。 然后,当用户选择一个项目时,您必须重新加载视图控制器数据,从而导致所有单元格被重绘,并将所选状态应用于其中一个单元格。

下面是我用来解决问题的代码的主旨,感谢Matt的耐心和帮助。

所有这些都可以位于主UICollectionView Controller类文件中,或者数据数组和结构可以位于自己的swift文件中,如果您需要在项目的其他位置使用它。

数据和数据模型:

let imagesArray=["image1", "image2", "image3", ...]

struct Model {
    var imageName : String
    var selectedState : Bool

    init(imageName : String, selectedState : Bool = false){
        self.imageName = imageName
        self.selectedState = selectedState
    }
}

UICollectionView控制器的代码

// create an instance of the data model for images and their status
var model = [Model]()

@IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() {
    super.viewDidLoad()

    // build out a data model instance based on the images array
    for i in 0..<imagesArray.count  {
        model.append(Model(imageName: imagesArray[i]))
        // the initial selectedState for all items is false unless otherwise set
    }

}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return imagesArray.count
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    // when the collectionview is loaded or reloaded...

    let cell:myCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! myCollectionViewCell

    // populate cells inside the collectionview with images 
    cell.imageView.image = UIImage(named: model[indexPath.item].imageName)

    // set the currently selected cell  (if one exists) to show its indicator styling
    if(model[indexPath.item].selectedState == true){
            cell.imageView.alpha = 1.0
        } else {
            cell.imageView.alpha = 0.5
    }

    return cell        
}

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {

    // when a cell is tapped...

    // reset all the selectedStates to false in the data model
    for i in 0..<imagesArray.count {
        model[i].selectedState = false
    }

    // set the selectedState for the tapped item to true in the data model
    model[indexPath.item].selectedState = true

    // refresh the collectionView (triggering cellForItemAtIndexPath above)
    self.collectionView.reloadData()

}

但是如果用户滚动它并不会持续存在,因为UI会在其他某个级别上重复使用该单元格

因为你做错了。 didSelect不对任何细胞进行任何更改 而是,更改基础数据模型 ,并重新加载集合视图。 这都是关于你的数据模型和你的cellForItemAtIndexPath:的实现cellForItemAtIndexPath: 这是单元格和插槽(项目和部分)相遇的地方。

这是一个简单的例子。 我们只有一个部分,因此我们的模型可以是模型对象的数组。 我将假设100行。 我们的模型对象只包含要进入此项目的图像名称,以及是否淡化此图像视图的知识:

struct Model {
    var imageName : String
    var fade : Bool
}
var model = [Model]()
override func viewDidLoad() {
    super.viewDidLoad()
    for i in 0..<100 {
        // ... configure a Model object and append it to the array
    }
}
override func collectionView(
    collectionView: UICollectionView, 
    numberOfItemsInSection section: Int) -> Int {
        return 100
}

现在,选择项目时会发生什么? 我会假设单一选择。 因此,在我们的模型中,该项目和其他项目都不应标记为淡入淡出。 然后我们重新加载数据:

override func collectionView(cv: UICollectionView, 
    didSelectItemAtIndexPath indexPath: NSIndexPath) {
        for i in 0..<100 {model[i].fade = false}
        model[indexPath.item].fade = true
        cv.reloadData()
}

所有实际工作都在cellForItemAtIndexPath:完成cellForItemAtIndexPath: 这项工作基于模型

override func collectionView(cv: UICollectionView,
    cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let c = self.collectionView!.dequeueReusableCellWithReuseIdentifier(
            "Cell", forIndexPath: indexPath) as! MyCell
        let model = self.model[indexPath.item]
        c.iv.image = UIImage(named:model.imageName)
        c.iv.alpha = model.fade ? 0.5 : 1.0
        return c
}

你的逻辑不正确。 didSelectItemAtIndexPath用于在选择单元格时触发某些内容。 所有这个功能都应该包含:

let cell:stkCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! stkCollectionViewCell

cell.imageView.alpha = 1.0

selectedIndex = indexPath.item

然后在您的cellForItemAtIndexPath函数中,您应该具有设置单元格的逻辑,因为这是重用单元格的位置。 所以这个逻辑应该在那里:

if (indexPath.item == selectedIndex){
    print(selectedIndex)
    cell.imageView.alpha = 1.0
} 
else {
    cell.imageView.alpha = 0.5
}

暂无
暂无

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

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