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
状态
在包含collectionView
的UIView
class中,我创建了一个函数来管理单元格的交互,即所有包含时间低于当前的必须有 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 时遇到了问题。
我需要获取 collectionView
的 firstIndex,其中 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)
]
}
大家好,我正在使用显示 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
状态
在包含collectionView
的UIView
class中,我创建了一个函数来管理单元格的交互,即所有包含时间低于当前的必须有 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 时遇到了问题。
我需要获取 collectionView
的 firstIndex,其中 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)
]
}