UIcollectionview 一次选择多个单元格

Posted

技术标签:

【中文标题】UIcollectionview 一次选择多个单元格【英文标题】:UIcollection view bug of selecting more than one cells at a time 【发布时间】:2020-05-23 12:14:43 【问题描述】:

我正在创建一个 7 天的日历。我正在使用包含 7 个单元格的集合视图,但是当我选择集合视图的最后一个单元格并滚动到第一个单元格时,最后一个单元格保持选中状态,并且第一个单元格也被选中。这是我得到的错误的屏幕截图。 enter image description hereenter image description here 这是我的主视图控制器中的代码

   `import UIKit
    import Foundation

    class ScheduleViewController: UIViewController 
        let top = UIColor(red: 217/255, green: 30/255, blue: 133/255, alpha: 1)
        let bottom = UIColor(red: 242/255, green: 56/255, blue: 15/255, alpha: 1)
        let todayColor = UIColor(red: 242/255, green: 56/255, blue: 15/255, alpha: 1)
        //    let otherDayColor = UIColor(red: 90/255, green: 90/255, blue: 90/255, alpha: 1)
        let otherDayColor = UIColor(red: 242/255, green: 56/255, blue: 15/255, alpha: 1)
        var now = Date()
        var day = DateFormatter()


        let dateHeading: UILabel = 
            let heading = UILabel()
            heading.text = "Date"
            heading.font = UIFont(name: "Roboto-Medium", size: 20)
            heading.translatesAutoresizingMaskIntoConstraints = false
            heading.numberOfLines = 0
            heading.adjustsFontSizeToFitWidth = true
            return heading
        ()
        fileprivate let collectionView: UICollectionView = 
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .horizontal
            let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
            cv.backgroundColor = .clear
            cv.translatesAutoresizingMaskIntoConstraints = false
            cv.register(CalendarCell.self, forCellWithReuseIdentifier: "CellID")
            return cv
        ()

        let bookButton: UIButton = 
            let button = UIButton(type: .system)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.setTitle("Book", for: .normal)
            button.titleLabel?.font = UIFont(name: "Roboto-Medium", size: 22)
            button.layer.cornerRadius = 5
            button.setTitleColor(.white, for: .normal)
            return button
        ()

        override func viewDidLoad() 
            super.viewDidLoad()
            view.backgroundColor = .black
            setupNavigationBar()
            view.addSubview(bookButton)
            bookButtonLayout()
            view.addSubview(collectionView)
            collectionViewLayout()
            configureCollectionView()
            collectionView.selectItem(at: IndexPath(row: 0, section: 0), animated: true, scrollPosition: [])
            view.addSubview(dateHeading)
            dateHeadingLayout()
            let gradientWidth = (UIScreen.main.bounds.width - 40)
            let gradientLayer = CAGradientLayer()
            gradientLayer.colors = [top.cgColor, bottom.cgColor]
            gradientLayer.locations = [0.15, 1]
            gradientLayer.startPoint = CGPoint(x: 0, y: 0)
            gradientLayer.endPoint = CGPoint(x: 1, y: 0)
            gradientLayer.frame = CGRect(x: 0, y: 0, width: gradientWidth, height: 44)
            gradientLayer.cornerRadius = 5
            bookButton.layer.insertSublayer(gradientLayer, at: 0)

        


        func myCalender(numDay: Int) -> Date 
            var dateComponents = DateComponents()
            dateComponents.setValue(numDay, for: .day); // +1 day

            let tomorrow = Calendar.current.date(byAdding: dateComponents, to: now)

            return tomorrow!
        

        func setupNavigationBar()
            self.navigationItem.title = "Schedule"
            self.navigationController?.navigationBar.prefersLargeTitles = true
            self.navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
        

        func collectionViewLayout()
            collectionView.heightAnchor.constraint(equalToConstant: 85).isActive = true
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
            collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true

        

        func configureCollectionView()
            collectionView.delegate = self
            collectionView.dataSource = self

        

        func dateHeadingLayout()
            dateHeading.heightAnchor.constraint(equalToConstant: 26).isActive = true
            dateHeading.widthAnchor.constraint(equalToConstant: 42).isActive = true
            dateHeading.bottomAnchor.constraint(equalTo: collectionView.topAnchor, constant: -5).isActive = true
            dateHeading.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
        


        func bookButtonLayout()
            bookButton.heightAnchor.constraint(equalToConstant: 44).isActive = true
            bookButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
            bookButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
            bookButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -30).isActive = true
        
    
    extension ScheduleViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource 

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
            return CGSize(width: 70, height: 75)
        

        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
            return 7
        

        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) 
            let cell = collectionView.cellForItem(at: indexPath) as? CalendarCell
            if cell?.isSelected == true
                cell?.backgroundColor = todayColor
                cell?.dateLabel.textColor = UIColor.white.withAlphaComponent(1)
                cell?.dayLabel.textColor = UIColor.white.withAlphaComponent(1)
                cell?.isOpaque = false
            
        

        func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) 
            let cell = collectionView.cellForItem(at: indexPath) as? CalendarCell
            if cell?.isSelected == false
                cell?.backgroundColor = .clear
                cell?.dateLabel.textColor = UIColor.white.withAlphaComponent(0.5)
                cell?.dayLabel.textColor = UIColor.white.withAlphaComponent(0.5)
                cell?.isOpaque = false
            
        

        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellID", for: indexPath) as! CalendarCell
            cell.layer.cornerRadius = 5
            cell.dateLabel.textColor = UIColor.white.withAlphaComponent(0.5)
            cell.dayLabel.textColor = UIColor.white.withAlphaComponent(0.5)
            cell.isOpaque = false

            if cell.isSelected == true
                cell.backgroundColor = todayColor
                cell.dateLabel.textColor = UIColor.white.withAlphaComponent(1)
                cell.dayLabel.textColor = UIColor.white.withAlphaComponent(1)
                cell.isOpaque = false
            

            if indexPath.row == 0
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: Date()) - 1])
                cell.dateLabel.text = now.string(format: "dd")
            
            else if indexPath.row == 1
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: myCalender(numDay: 1)) - 1])
                cell.dateLabel.text = myCalender(numDay: 1).string(format: "dd")
            
            else if indexPath.row == 2
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: myCalender(numDay: 2)) - 1])
                cell.dateLabel.text = myCalender(numDay: 2).string(format: "dd")
            
            else if indexPath.row == 3
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: myCalender(numDay: 3)) - 1])
                cell.dateLabel.text = myCalender(numDay: 3).string(format: "dd")
            
            else if indexPath.row == 4
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: myCalender(numDay: 4)) - 1])
                cell.dateLabel.text = myCalender(numDay: 4).string(format: "dd")
            
            else if indexPath.row == 5
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: myCalender(numDay: 5)) - 1])
                cell.dateLabel.text = myCalender(numDay: 5).string(format: "dd")
            
            else if indexPath.row == 6
                cell.dayLabel.text = (day.shortWeekdaySymbols[Calendar.current.component(.weekday, from: myCalender(numDay: 6)) - 1])
                cell.dateLabel.text = myCalender(numDay: 6).string(format: "dd")
            
            cell.isSelected = (cellStatus[indexPath.row] as? Bool) ?? false
            return cell
        

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
            return 5
        


    
    extension Date 
        func string(format: String) -> String 
            let formatter = DateFormatter()
            formatter.timeZone = .current
            formatter.dateFormat = format
            formatter.shortWeekdaySymbols = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
            return formatter.string(from: self)
        
    `

这是我的自定义日历单元代码

`import UIKit
class CalendarCell: UICollectionViewCell 
    let dateLabel: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont(name: "Roboto-Medium", size: 30)
        label.textColor = .white
        label.textAlignment = .center
        label.adjustsFontSizeToFitWidth = true
        label.numberOfLines = 0
        return label
    ()

    let dayLabel: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont(name: "Roboto-Medium", size: 20)
        label.textColor = .white
        label.textAlignment = .center
        label.adjustsFontSizeToFitWidth = true
        label.numberOfLines = 0
        return label
    ()


    override init(frame: CGRect) 
        super.init(frame: frame)

        contentView.layer.cornerRadius = 5
        contentView.addSubview(dayLabel)
        dayLabelLayout()
        contentView.addSubview(dateLabel)
        dateLabelLayout()
    

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

    func dateLabelLayout()
        dateLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5).isActive = true
        dateLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
        dateLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
        dateLabel.bottomAnchor.constraint(equalTo: dayLabel.topAnchor).isActive = true
    

    func dayLabelLayout()
        dayLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5).isActive = true
        dayLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5).isActive = true
        dayLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5).isActive = true
        dayLabel.heightAnchor.constraint(equalToConstant: 20).isActive = true


    


`

【问题讨论】:

您找到解决方案了吗? 【参考方案1】:

那个单元格被重用而不是被选中......但是由于重用......它的 backgroundColor , dateLabel , dayLabel 和 isOpaque 改变了

在您的CalendarCell 中.. 使用未选中单元格的默认值覆盖此函数..

 override func prepareForReuse() 
        super.prepareForReuse()
        backgroundColor = .white//defaultValue
        dateLabel.textColor = UIColor.white.withAlphaComponent(1) // default value
        cell?.dayLabel.textColor = UIColor.white.withAlphaComponent(1) // default value
        cell?.isOpaque = false // default value
    

【讨论】:

永远不要!忘记打电话给超级! super.prepareForReuse()

以上是关于UIcollectionview 一次选择多个单元格的主要内容,如果未能解决你的问题,请参考以下文章

在 UIcollectionview 中使多个单元格出列的方法

一个UIViewController中的多个UICollectionView数据源

UICollectionView 在单元格上拖动手指以选择它们

具有多个部分的 UICollectionView

在第二次点击时取消选择 UICollectionView 单元格

UICollectionView 水平对齐滚动第一个单元格中心对齐第一次使用 Swift 时不完全放置中心位置