pre select/highlight UICollectionViewCell 在第一次加载视图时

pre select/highlight UICollectionViewCell on first load of view

我正在尝试预选 UICollectionView 中的第一个 object/UICollectionViewCell?我试过:

self.dateCollectionView.allowsMultipleSelection=NO;

[self.dateCollectionView selectItemAtIndexPath:0 animated:YES scrollPosition:UICollectionViewScrollPositionLeft];
[self collectionView:self.dateCollectionView didSelectItemAtIndexPath:0];
[self.dateCollectionView reloadData];

viewDidLoad.

这是我的 UICollectionView 方法;

 -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

  return self.titles.count;
 }

 -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    cell.backgroundColor= [UIColor clearColor];
    UILabel * dateLabel = (UILabel *)[cell viewWithTag:1];
    UILabel * subText = (UILabel *)[cell viewWithTag:2];
    subText.text=self.titles[indexPath.row];
    subText.adjustsFontSizeToFitWidth=YES;
    if (cell.selected) {
        cell.backgroundColor = [UIColor blueColor]; // highlight selection
    }
    else
    {
        cell.backgroundColor = [UIColor redColor]; // Default color
    }
    return cell;
}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath  {

    UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
    datasetCell.backgroundColor = [UIColor blueColor]; // highlight selection
}

-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {

 UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
datasetCell.backgroundColor = [UIColor redColor]; // Default color
}

- (BOOL)collectionView:(UICollectionView *)collectionView
 shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return YES;
}

- (BOOL)collectionView:(UICollectionView *)collectionView
 shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
{
    return YES;
}

viewDidAppear中:

NSIndexPath *indexPathForFirstRow = [NSIndexPath indexPathForRow:0 inSection:0];
[self.dateCollectionView selectItemAtIndexPath:indexPathForFirstRow animated:NO scrollPosition:UICollectionViewScrollPositionNone];
[self collectionView:self.dateCollectionView didSelectItemAtIndexPath:indexPathForFirstRow];

对于 Swift 3:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    //auto selected 1st item
    let indexPathForFirstRow = IndexPath(row: 0, section: 0)
    self.collectionView?.selectItem(at: indexPathForFirstRow, animated: true, scrollPosition: .top)
}

swift 最初选择单元格的代码

func selectinitialCell() {

    let cell = venueTypeCollectionView.cellForItemAtIndexPath(NSIndexPath(forItem: 0, inSection: 0)) as! SearchTypeCollectionViewCell
    self.indexPathOfSelectedItem = NSIndexPath(forItem: 0, inSection: 0)
    cell.venueType.textColor = UIColor.whiteColor()
    cell.selected = true
}

但这并没有调用didSelectItemAtIndexPath、didDeselectItemAtIndexPath等委托函数。

对于Swift 3.0.1 你可以试试这个:

self.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])

self.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition(rawValue: 0))

对于Objective-C你可以试试这个:

self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];

注意:你应该在viewDidAppear

中使用它

为swift3

使用collectionView.selectItemwith-in这个重载collectionView(UICollectionView, IndexPath)

这是我的代码,在这段代码中我预先选择了带有 indexPath.row = 0

的行
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = ScenarioCollectionView.dequeueReusableCell(withReuseIdentifier: "ReuseScenarioCollectionViewCell", for: indexPath as IndexPath) as! ScenarioCollectionViewCell

    if (indexPath.row == 0){
        collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
        cell.layer.borderColor=UIColor.gray.cgColor        
    }else{
        cell.layer.borderColor=UIColor.white.cgColor
    }
    return cell
}


func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.layer.borderColor = UIColor.gray.cgColor
        }

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath as IndexPath)
    cell?.layer.borderColor = UIColor.white.cgColor
    collectionView.deselectItem(at: indexPath, animated: true)
}

对我来说,把它放在 viewDidAppear: 会导致 select 秒,所以用户会看到两种状态(即未 selected 和 selected ). 为避免这种情况,我将其放在 viewWillAppear: 中,效果很好

override func viewWillAppear(_ animated: Bool) {
    let selectedIndexPath = IndexPath(item: 0, section: 0)
    collectionView.selectItem(at: selectedIndexPath, animated: false, scrollPosition: .left)
}

我通过子类化 UICollectionView 并在 layoutSubviews 中选择需要的项目解决了这个问题:

class InitialSelectionCollectionView: UICollectionView {

   var initialSetupPerformed: Bool = false
   var initialSelectedIndexPath: IndexPath!

   override func layoutSubviews() {
       super.layoutSubviews()

       if !initialSetupPerformed && initialSelectedIndex != nil{
           selectItem(at: initialSelectedIndexPath, animated: false, scrollPosition: .centeredHorizontally)

           initialSetupPerformed = true
       }
   }
}

然后,当您初始化自定义集合视图时,只需将需要的 IndexPath 设置为 initialSelectedIndexPath

    [self.collectionView reloadData];
    [self.collectionView layoutIfNeeded]; //important
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
    [self.collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
    [self collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];

以我为例。我通过 subclass a UICollectionView class 和 Generic types

解决了它
// ******************************************
//
// MARK: - Config injection, Extend whatever you want
//
// ******************************************
struct CCCollectionViewConfig {
    var itemSize: CGSize?
    var minimumInteritemSpacing: CGFloat?
    var minimumLineSpacing: CGFloat?
    var allowsDefaultSelection: Bool = true
}

// ******************************************
//
// MARK: - Generic CCCollectionView
//
// ******************************************
final class CCCollectionView<T, Cell: UICollectionViewCell>: UICollectionView, UICollectionViewDataSource, UICollectionViewDelegate {

    typealias SelectHandler = (T, IndexPath?) -> Void

    typealias CellConfigure = (Cell, T) -> Void

    var contents: [T] = [] {
        didSet {
            DispatchQueue.main.async {
                self.reloadData()
                self.selectedIndexPath = IndexPath(item: (self.config.allowsDefaultSelection) ? 0 : -1, section: 0)
            }
        }
    }

    var configure: CellConfigure

    var selectHandler: SelectHandler

    var selectedIndexPath: IndexPath

    private var config: CCCollectionViewConfig

    private let identifier = "identifier"

    init(contents: [T], config: CCCollectionViewConfig, configure: @escaping CellConfigure, selectHandler: @escaping SelectHandler) {

        self.config = config
        self.contents = contents
        self.configure = configure
        self.selectHandler = selectHandler
        self.selectedIndexPath = IndexPath(item: (config.allowsDefaultSelection) ? 0 : -1, section: 0)

        let layout = UICollectionViewFlowLayout()

        if let size = config.itemSize {
            layout.itemSize = size
        }

        layout.minimumInteritemSpacing = config.minimumInteritemSpacing ?? 0
        layout.minimumLineSpacing = config.minimumLineSpacing ?? 0
        layout.scrollDirection = .vertical
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

        super.init(frame: .zero, collectionViewLayout: layout)

        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setup() {
        register(Cell.self, forCellWithReuseIdentifier: identifier)

        super.delegate = self
        super.dataSource = self

        allowsMultipleSelection = false
        isScrollEnabled = false
        backgroundColor = .clear
    }

    // ******************************************
    //
    // MARK: - UICollectionViewDataSource, UICollectionViewDelegate
    //
    // ******************************************

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! Cell
        cell.isSelected = (selectedIndexPath == indexPath)
        let content = contents[indexPath.row]
        configure(cell, content)
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        let content = contents[indexPath.row]
        selectHandler(content, indexPath)

        /// If selected item is equal to current selected item, ignore it
        if selectedIndexPath == indexPath {
            return
        }

        /// Handle selected cell
        let selectedCell = collectionView.cellForItem(at: indexPath)
        selectedCell?.isSelected = true

        /// Handle deselected cell
        let deselectItem = collectionView.cellForItem(at: selectedIndexPath)
        deselectItem?.isSelected = false

        selectedIndexPath = indexPath
    }
}

// ******************************************
//
// MARK: - CollectionViewCell
//
// ******************************************
final class CCCollectionViewCell: UICollectionViewCell {

    var title: String = "" {
        didSet {
            titleLabel.text = title
        }
    }

    private let titleLabel: UILabel = {
        let label = UILabel()
        return label
    }()


    var _isSelected: Bool = false
    override var isSelected: Bool {
        get {
            return _isSelected
        }
        set(newValue) {
            _isSelected = newValue
            updateSelection()
        }
    }

    private func updateSelection() -> Void {
        contentView.layer.borderColor = isSelected ? UIColor.red.cgColor : UIColor.green.cgColor
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(titleLabel)
        contentView.layer.cornerRadius = 2.0
        contentView.layer.borderWidth = 2.0
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

然后在你的 ViewController

中使用它
private let fakeContents = Array(repeating: "123123", count: 40)

/// Collection View Config
private lazy var config: CCCollectionViewConfig = {
    return CCCollectionViewConfig(itemSize: CGSize(width: 100, height: 30),
                                  minimumInteritemSpacing: 4.0,
                                  minimumLineSpacing: 4.0)
}()

/// Collection View Config
private lazy var collectionView: CCCollectionView<String, CCCollectionViewCell> = {
    let cv = CCCollectionView<String, CCCollectionViewCell>(contents: fakeContents, config: config, configure: { (cell: CCCollectionViewCell, content) in
        cell.title = content
    }) { [weak self] (content, indexPath) in
        guard let self = self else { return }
        guard let row = indexPath?.row else { return }
    }
    return cv
}()