Ios 确保UICollectionView中只有1个单元格处于活动状态

Ios 确保UICollectionView中只有1个单元格处于活动状态,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,我有一个UICollectionView,其中我只希望1个单元格处于活动状态。使用active,我的意思是:单击的最后一个单元格或要显示集合视图的第一个单元格。当用户单击非活动单元格时,我希望将旧的活动单元格重置为非活动状态。我做这件事有困难。这是因为集合视图的属性visibleCells只返回屏幕上的单元格,而不返回内存中的单元格。这是我当前定位活动单元格并将状态重置为非活动状态的方法 这种情况可能发生,导致多个活动单元格:用户稍微向下滚动,使当前活动单元格不再可见,点击随机单元格并向上滚动。

我有一个UICollectionView,其中我只希望1个单元格处于活动状态。使用active,我的意思是:单击的最后一个单元格或要显示集合视图的第一个单元格。当用户单击非活动单元格时,我希望将旧的活动单元格重置为非活动状态。我做这件事有困难。这是因为集合视图的属性visibleCells只返回屏幕上的单元格,而不返回内存中的单元格。这是我当前定位活动单元格并将状态重置为非活动状态的方法

这种情况可能发生,导致多个活动单元格:用户稍微向下滚动,使当前活动单元格不再可见,点击随机单元格并向上滚动。问题是,旧的活动单元格保留在内存中,尽管它不可见:cellForItemAt_u3;:不会为该单元格调用。坏消息是VisibleCell也找不到旧的活动单元格。我怎样才能找到它?函数willDisplay cell也不起作用

示例项目可以直接克隆到xCode:

这是示例项目中的代码:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: CollectionView!
    static var activeIndex = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.go()
    }
}

class Cell: UICollectionViewCell {
    @IBOutlet weak var button: MyButton!

}

class CollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource {
    func go() {
        delegate = self
        dataSource = self
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 500
    }

    internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
        if indexPath.row == ViewController.activeIndex {
            cell.button.setTitle("active", for: .normal)
        } else {
            cell.button.setTitle("not active", for: .normal)
        }
        cell.button.addTarget(self, action: #selector(touchUpInside(_:)), for: .touchUpInside)
        return cell
    }

    @objc private func touchUpInside(_ sender: UIButton){
        let hitPoint = sender.convert(CGPoint.zero, to: self)
        guard let indexPath = indexPathForItem(at: hitPoint), let cell = cellForItem(at: indexPath) as? Cell else { return }

        // This is the problem. It does not finds the current active cell
        // if it is just out of bounds. Because it is in memory, cellForItemAt: does not gets called
        if let oldCell = (visibleCells as! [Cell]).first(where: { $0.button.titleLabel!.text == "active" }) {
            oldCell.button.setTitle("not active", for: .normal)
        }

        cell.button.setTitle("active", for: .normal)

        ViewController.activeIndex = indexPath.row
    }

}
您可以使用UICollectionViewCell的isSelected属性。如果选择了活动布局,则可以将其设置为单元格。默认情况下,选择机制在UICollectionViewCell中实现。如果要选择/激活多个单元格,可以将属性allowsMultipleSelection设置为true

基本上,这种方法如下所示:

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: CollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.go()
    }

    func activeIndex()->Int?{
        if let selectedItems = self.collectionView.indexPathsForSelectedItems {
            if selectedItems.count > 0{
                return selectedItems[0].row
            }
        }
        return nil
    }
}

class Cell: UICollectionViewCell {

    @IBOutlet weak var myLabel: UILabel!

    override var isSelected: Bool{
        didSet{
            if self.isSelected
            {
                myLabel.text = "active"
            }
            else
            {
                myLabel.text = "not active"
            }
        }
    }
}


class CollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource {
    func go() {
        delegate = self
        dataSource = self
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 500
    }

    internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! Cell
        return cell
    }
}

要从这个故障中恢复,您可以在cellForRowAt中尝试

单击按钮时,设置

ViewController.activeIndex = sender.tag
self.reloadData()

它不起作用。我可以有多个属性设置为true的单元格。我有一个可以在5秒钟内克隆的示例项目看我的问题,也许你可以看看你是否能让它工作:我已经用建议的方法更新了我的答案。我不知道为什么我没有考虑在过去2小时内重新加载数据-谢谢:D.为了节省一些内存,我在现有代码中添加了一条else语句:if let oldCell=visibleCells as![Cell].firstwhere:{$0.button.titleLabel!.text==active}{oldCell.button.setTitlenot active,for:.normal}其他{reloadItemsat:[InExpathrow:ViewController.activeIndex,section:0]}是的,节省内存很好,事实上,这个小故障使我即使在消耗内存的情况下也难以实现:D
ViewController.activeIndex = sender.tag
self.reloadData()