Ios 确保UICollectionView中只有1个单元格处于活动状态
我有一个UICollectionView,其中我只希望1个单元格处于活动状态。使用active,我的意思是:单击的最后一个单元格或要显示集合视图的第一个单元格。当用户单击非活动单元格时,我希望将旧的活动单元格重置为非活动状态。我做这件事有困难。这是因为集合视图的属性visibleCells只返回屏幕上的单元格,而不返回内存中的单元格。这是我当前定位活动单元格并将状态重置为非活动状态的方法 这种情况可能发生,导致多个活动单元格:用户稍微向下滚动,使当前活动单元格不再可见,点击随机单元格并向上滚动。问题是,旧的活动单元格保留在内存中,尽管它不可见:cellForItemAt_u3;:不会为该单元格调用。坏消息是VisibleCell也找不到旧的活动单元格。我怎样才能找到它?函数willDisplay cell也不起作用 示例项目可以直接克隆到xCode: 这是示例项目中的代码:Ios 确保UICollectionView中只有1个单元格处于活动状态,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,我有一个UICollectionView,其中我只希望1个单元格处于活动状态。使用active,我的意思是:单击的最后一个单元格或要显示集合视图的第一个单元格。当用户单击非活动单元格时,我希望将旧的活动单元格重置为非活动状态。我做这件事有困难。这是因为集合视图的属性visibleCells只返回屏幕上的单元格,而不返回内存中的单元格。这是我当前定位活动单元格并将状态重置为非活动状态的方法 这种情况可能发生,导致多个活动单元格:用户稍微向下滚动,使当前活动单元格不再可见,点击随机单元格并向上滚动。
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()