Select UICollectionView 中的第一个索引

Select FirstIndex in UICollectionView

大家好,我正在使用显示 19 个单元格的 UICollectionView。 单元格显示时间列表


我通过模型 (TimeSelModel) 管理我的数据

TimeSelModel.swift

struct Section<T> { let dataModel: [T] }

struct TimeSelModel {
    let hour: Int 
    let minute: Int 
    var time: String { "\(hour):\(minute)" }
    var cellInteraction: Bool = true
}

let dataSec0 = [ // Dati della sezione 0
    TimeSelModel(hour: 09, minute: 30),
    TimeSelModel(hour: 10, minute: 00),
    TimeSelModel(hour: 10, minute: 30),
    TimeSelModel(hour: 11, minute: 00),
    TimeSelModel(hour: 11, minute: 30),
    TimeSelModel(hour: 15, minute: 00),
    TimeSelModel(hour: 15, minute: 30),
    TimeSelModel(hour: 16, minute: 00),
    TimeSelModel(hour: 16, minute: 30),
    TimeSelModel(hour: 17, minute: 00)
]

let dataSec1 = [ // Dati della sezione 1
    TimeSelModel(hour: 12, minute: 00),
    TimeSelModel(hour: 12, minute: 30),
    TimeSelModel(hour: 13, minute: 00),
    TimeSelModel(hour: 14, minute: 00),
    TimeSelModel(hour: 14, minute: 30),
    TimeSelModel(hour: 17, minute: 30),
    TimeSelModel(hour: 18, minute: 00),
    TimeSelModel(hour: 18, minute: 30),
    TimeSelModel(hour: 19, minute: 00)
]

var cellInteraction 分配 collectionView

的单元格的 isUserInteractionEnable 状态

在包含collectionViewUIViewclass中,我创建了一个函数来管理单元格的交互,即所有包含时间低于当前的必须有 cellInteraction == false

TimeSelView.swift

private var data: [Section<TimeSelModel>] = []


private func isPreviousTime(_ values: (Int, Int)) -> Bool {
    guard let time = Calendar.current.date(bySettingHour: values.0, minute: values.1, second: 0, of: Date()) else {
        // Non è stato possibile determinare l'orario prescelto
        return false
    }
    
    return time < Date()
}


// MARK: Update Cell Status
    private func updateCellStatus() {
        
        var sec: Int = 0
        var hour: Int = 0
        var minute: Int = 0
                        
        (0..<data.count).forEach { (section) in
            
            sec = section

            (0..<data[section].dataModel.count).forEach { (values) in
                
                hour = data[section].dataModel[values].hour
                minute = data[section].dataModel[values].minute
                
                data[section].dataModel[values].cellInteraction = isPreviousTime((hour, minute)) ? false : true
            }
        }
                
        cv.reloadData()
       
        // GET FIRST INDEX WHERE cellInteraction == TRUE

        if let index = data[sec].dataModel.firstIndex(where: { [=12=].cellInteraction }) {
            cv.selectItem(at: IndexPath(item: index, section: sec), animated: false, scrollPosition: [])

            print(sec)
            // SEC is always 1 .. this is wrong
        }
    }

正如您从图片中看到的那样,一切正常,但我在使用 selection 时遇到了问题。

我需要获取 collectionViewfirstIndex,其中 cellInteraction == TRUE.

根据我向您展示的图像,应该 select 包含时间 11:30 的单元格而不是继续 select 包含 12:00,这是因为它总是在循环中保持returning section 1,我不明白为什么

我现在哪里错了?为什么它总是 return 第 1 节而它应该(在这种情况下)return 第 0 节和 select 包含 11:30 的单元格?


在自定义单元格中class我将cellInteraction的值分配给单元格的isUserInteractionEnable

TimeSelCell.swift

class TimeSelCell: UICollectionViewCell {
    
    static let cellID = "time.selector.cell.identifier"
    private let minuteLbl = UILabel(font: .systemFont(ofSize: 13), textColor: .white, textAlignment: .center)
    private let hourLbl = UILabel(font: .boldSystemFont(ofSize: 17), textColor: .white, textAlignment: .center)
    
    var dataModel: TimeSelModel! {
        didSet {
            
            hourLbl.text = String(format: "%02d", dataModel.hour)
            minuteLbl.text = ":" + String(format: "%02d", dataModel.minute)
            
            isUserInteractionEnabled = dataModel.cellInteraction
            contentView.alpha = dataModel.cellInteraction ? 1 : 0.5
        }
    }

您只计算数据中的 last 数组:

// MARK: Update Cell Status
private func updateCellStatus() {
    
    var sec: Int = 0
    var hour: Int = 0
    var minute: Int = 0
    
    (0..<data.count).forEach { (section) in
        
        // set sec equal to section, which will increment each
        //  time through this loop
        sec = section
        
        (0..<data[section].dataModel.count).forEach { (values) in
            
            hour = data[section].dataModel[values].hour
            minute = data[section].dataModel[values].minute
            
            data[section].dataModel[values].cellInteraction = isPreviousTime((hour, minute)) ? false : true
        }
    }
    
    cv.reloadData()

    // NOTE:
    //      
    // the var "sec" now equals data.count
    // 
    // 
    
    // GET FIRST INDEX WHERE cellInteraction == TRUE
    
    if let index = data[sec].dataModel.firstIndex(where: { [=10=].cellInteraction }) {
        cv.selectItem(at: IndexPath(item: index, section: sec), animated: false, scrollPosition: [])
        
        print(sec)
        // SEC is always 1 .. this is wrong
    }
}

因此,当您退出 that 循环时,您想再次循环这些部分,检查第一个匹配项:

    cv.reloadData()

    // GET FIRST INDEX WHERE cellInteraction == TRUE

    var foundSection: Int = -1
    var foundIndex: Int = -1
    
    for section in 0..<data.count {
        if let index = data[section].dataModel.firstIndex(where: { [=11=].cellInteraction }) {
            foundSection = section
            foundIndex = index
            break
        }
    }

    // if section and index are "-1" (so you'll only need to check one of them)
    //  no object found with cellInteraction == true
    if foundSection == -1 {
        print("No objects found with cellInteraction == true!!!")
    } else {
        print("Found First -- Section:", foundSection, "Index:", foundIndex)
    }

编辑 - 评论后

要获取hour/min 最接近当前时间(的对象(hour/min),创建一个包含部分、索引和 时间差 的新结构,然后找到具有最小差异的对象。

// MARK: Update Cell Status
private func updateCellStatus() {
    
    struct DiffStruct {
        var section: Int = 0
        var index: Int = 0
        var timeDiff: TimeInterval = 0
    }
    
    var tempArray: [DiffStruct] = []
    
    var hour: Int = 0
    var minute: Int = 0
    
    (0..<data.count).forEach { (section) in
        
        (0..<data[section].dataModel.count).forEach { (values) in
            
            hour = data[section].dataModel[values].hour
            minute = data[section].dataModel[values].minute
            
            // get a valid Date object
            if let time = Calendar.current.date(bySettingHour: hour, minute: minute, second: 0, of: Date()) {
                // create a DiffStruct object, setting .timeDiff to
                //  this TimeSelModel's time minus the current time
                let ds = DiffStruct(section: section, index: values, timeDiff: time.timeIntervalSinceReferenceDate - curTime.timeIntervalSinceReferenceDate)
                // append it to the tempArray
                tempArray.append(ds)
                // set .cellInteraction to TRUE if .timeDiff is greater-than-or-equal to Zero
                data[section].dataModel[values].cellInteraction = ds.timeDiff >= 0
            } else {
                // could not create a Date from hour/minute
                //  so set .cellInteraction to false
                data[section].dataModel[values].cellInteraction = false
            }
        }
    }
    
    //cv.reloadData()

    // instead of:      
    //     GET FIRST INDEX WHERE cellInteraction == TRUE

    // we want to:
    //     Get the object where its time is CLOSEST to the current time
    //     without being LATER

    // use only Positive timeDiffs (so we're only looking at LATER times)
    let tmp: [DiffStruct] = tempArray.filter({ [=12=].timeDiff >= 0})
    // get the object with the smallest timeDiff
    if let first = tmp.min(by: { [=12=].timeDiff < .timeDiff } ) {
        print("Closest Match is Sec:", first.section, "Idx:", first.index)
    } else {
        print("No objects found with hour/min greater than current hour/min !!!")
    }

}

编辑 2 -- 更多评论后

我重新编写了代码,使它更清楚发生了什么(也避免了额外的 .filter 步骤):

// MARK: Update Cell Status
private func updateCellStatus(with curTime: Date) -> (section: Int, index: Int)? {
    
    struct DiffStruct {
        var section: Int = 0
        var index: Int = 0
        var timeDiff: TimeInterval = 0
    }
    
    var tempArray: [DiffStruct] = []
    
    (0..<data.count).forEach { (section) in
        
        (0..<data[section].dataModel.count).forEach { (index) in
            
            let thisModel = data[section].dataModel[index]
            
            let hour = thisModel.hour
            let minute = thisModel.minute
            
            // get a valid Date object
            if let time = Calendar.current.date(bySettingHour: hour, minute: minute, second: 0, of: Date()) {
                
                // get difference between thisModel's time and curTime
                let diff = time.timeIntervalSinceReferenceDate - curTime.timeIntervalSinceReferenceDate
                
                if diff >= 0 {

                    // if diff is >= 0,
                    //  thisModel's time is LATER than curTime (or equal to)

                    // set .cellInteraction to TRUE if .timeDiff is greater-than-or-equal to Zero
                    data[section].dataModel[index].cellInteraction = true

                    // create a DiffStruct object
                    let ds = DiffStruct(section: section, index: index, timeDiff: diff)
                    
                    // append it to the tempArray
                    tempArray.append(ds)
                    
                } else {

                    // set .cellInteraction to FALSE
                    data[section].dataModel[index].cellInteraction = false
                    
                }

            } else {
                // could not create a Date from hour/minute
                //  so set .cellInteraction to false
                data[section].dataModel[index].cellInteraction = false
            }
            
        }
        
    }
    
    // we've udpated .cellInteraction for all models, so
    //cv.reloadData()
    
    // get the object with the smallest timeDiff
    if let first = tempArray.min(by: { [=13=].timeDiff < .timeDiff } ) {
        return (first.section, first.index)
    }
    
    // No objects found with hour/min greater than current hour/min !!!
    return nil

}

你可以这样测试:

class TestViewController: UIViewController {

    private var data: [Section<TimeSelModel>] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        data.append(Section(dataModel: dataSec0))
        data.append(Section(dataModel: dataSec1))
        
        // start at 09:23
        var currentTime: Date = Calendar.current.date(bySettingHour: 9, minute: 23, second: 0, of: Date())!
        
        for _ in 1...24 {
            
            let h = Calendar.current.component(.hour, from: currentTime)
            let m = Calendar.current.component(.minute, from: currentTime)
            
            if let p = updateCellStatus(with: currentTime) {
                let theModel = data[p.section].dataModel[p.index]
                print("Closest to \(h):\(m) is Section:", p.section, "Index:", p.index, "--", theModel.time)
            } else {
                print("\(h):\(m) is Later than all times!!!")
            }
            
            // add a half-hour
            currentTime = currentTime.addingTimeInterval(30 * 60)
            
        }

    }

    struct Section<T> { var dataModel: [T] }
    
    struct TimeSelModel {
        let hour: Int
        let minute: Int
        var time: String { "\(hour):\(minute)" }
        var cellInteraction: Bool = true
    }
    
    var dataSec0 = [ // Dati della sezione 0
        TimeSelModel(hour: 09, minute: 30),
        TimeSelModel(hour: 10, minute: 00),
        TimeSelModel(hour: 10, minute: 30),
        TimeSelModel(hour: 11, minute: 00),
        TimeSelModel(hour: 11, minute: 30),
        TimeSelModel(hour: 15, minute: 00),
        TimeSelModel(hour: 15, minute: 30),
        TimeSelModel(hour: 16, minute: 00),
        TimeSelModel(hour: 16, minute: 30),
        TimeSelModel(hour: 17, minute: 00)
    ]
    
    var dataSec1 = [ // Dati della sezione 1
        TimeSelModel(hour: 12, minute: 00),
        TimeSelModel(hour: 12, minute: 30),
        TimeSelModel(hour: 13, minute: 00),
        TimeSelModel(hour: 14, minute: 00),
        TimeSelModel(hour: 14, minute: 30),
        TimeSelModel(hour: 17, minute: 30),
        TimeSelModel(hour: 18, minute: 00),
        TimeSelModel(hour: 18, minute: 30),
        TimeSelModel(hour: 19, minute: 00)
    ]

}