在第一次加载视图时预选择/突出显示 UICollectionViewCell

Posted

技术标签:

【中文标题】在第一次加载视图时预选择/突出显示 UICollectionViewCell【英文标题】:pre select/highlight UICollectionViewCell on first load of view 【发布时间】:2015-04-23 14:34:26 【问题描述】:

我试图在 UICollectionView 中预选第一个对象/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;

【问题讨论】:

【参考方案1】:

viewDidAppear:

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

【讨论】:

【参考方案2】:

对于 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

中使用它

【讨论】:

【参考方案3】:

对于 swift 3

在这个重载collectionView(UICollectionView, IndexPath)中使用collectionView.selectItem

这是我的代码,在此代码中,我预先选择了带有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)

【讨论】:

【参考方案4】:

我通过子类化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

【讨论】:

【参考方案5】:

对我来说,将其放入 viewDidAppear: 会导致第二次选择,因此用户将看到两种状态(即未选择和已选择)。 为了避免这种情况,我把它放在viewWillAppear: 中,并像魅力一样工作

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

【讨论】:

【参考方案6】:

对于 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)

【讨论】:

【参考方案7】:
    [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];

【讨论】:

layoutIfNeeded 拯救了我的一天!【参考方案8】:

用于初始选择单元格的快速代码

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等委托函数。

【讨论】:

【参考方案9】: Here is full code link

就我而言。我通过带有Generic typesUICollectionView 类的子类解决了它

// ******************************************
//
// 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
()

【讨论】:

以上是关于在第一次加载视图时预选择/突出显示 UICollectionViewCell的主要内容,如果未能解决你的问题,请参考以下文章

突出显示表格视图单元格 TextLabel 文本颜色

如何让 Tomcat 在启动时预编译 JSP?

在应用程序启动时预加载 UITabBar 选项卡时出现问题(崩溃)

如何选择/突出显示列表视图中的项目而不触摸它?

目标 C:如何在视图加载时突出显示表格视图中的第一个单元格?

关闭块不会在第二次 swift3 上重新加载表