如何访问 UICollectionViewController header 中的 UISegmentedControl?
How can I access UISegmentedControl in header of UICollectionViewController?
所以这个问题很简单。我有一个 UICollectionViewController
(MyProfile.swift)
和一个 header 部分 (MyProfileHeader.swift)
。在后者中,我有一个 UISegmentedControl
到 return 不同数量的项目和 collection view cells
中的项目(我不想在 class 中初始化后者的实例UICollectionViewController
)。这是我 MyProfile.swift class
的代码。我尝试在 viewForSupplementaryElementOfKind
方法中将目标添加到 return 不同的查询(有效),但我最终必须在 numberOfItemsInSection
和 cellForItemAtIndexPath
方法中访问分段控件。 "testObjects"
和 "writeObjects"
是 array
值,通过 viewForSupplementaryElementOfKind
中的 addTarget
方法查询。我设置了 indexPath
但它 returns
一个 error
出于显而易见的原因......我如何访问分段控制?
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
var numberOfItems: Int? = 0
let indexPath = NSIndexPath(forItem: 0, inSection: 0)
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "header", forIndexPath: indexPath) as! MyProfileHeader
if header.userContent.selectedSegmentIndex == 1 {
numberOfItems = textObjects.count
} else if header.userContent.selectedSegmentIndex == 2 {
numberOfItems = 0
} else {
numberOfItems = photoObjects.count
}
print("F: \(numberOfItems!)")
return numberOfItems!
}
当在 viewForSupplementaryElementOfKind
中为 collection 视图检索到 header 时,您可以在 MyProfile
中存储对它的弱引用。
class MyProfile: UICollectionViewController {
...
...
weak var header: MyProfileHeader?
...
...
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "header", forIndexPath: indexPath) as! MyProfileHeader
return header
}
然后您可以从 UICollectionViewController
中的任何其他功能访问它。
请注意,numberOfItemsInSection
和 cellForItemAtIndexPath
可以在 viewForSupplementaryElementOfKind
中创建 header 之前调用,因此当您在 numberOfItemsInSection
中访问它时, cellForItemAtIndexPath
,或您应该检查 null 的其他任何地方,然后假定分段控件处于默认值(因为这是第一次显示视图,所以它会是默认值)。像
let selectedSegmentIndex = header?.userContent.selectedSegmentIndex ?? 0 //0 is the default value here
-1st 创建一个 UICollectionReusableView
subclass 并将其命名为 SegmentedHeader
-2nd 在 SegmentedHeader class 中添加一个协议来跟踪选择了哪个段。当在 collectionView 的 header 中选择一个段时,protocol/delegate 将传递该段的值
-3rd 确保设置委托 weak var delegate: SegmentedHeaderDelegate?
-4th 在以编程方式创建 segmentedControl
时添加一个名为 selectedIndex(_ sender: UISegmentedControl) 的目标。当一个片段被按下时,你将该片段的值传递给协议 trackSelectedIndex() 函数
protocol SegmentedHeaderDelegate: class {
func trackSelectedIndex(_ theSelectedIndex: Int)
}
class SegmentedHeader: UICollectionReusableView {
//MARK:- Programmatic Objects
let segmentedControl: UISegmentedControl = {
let segmentedControl = UISegmentedControl(items: ["Zero", "One", "Two"])
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.tintColor = UIColor.red
segmentedControl.backgroundColor = .white
segmentedControl.isHighlighted = true
segmentedControl.addTarget(self, action: #selector(selectedIndex(_:)), for: .valueChanged)
return segmentedControl
}()
//MARK:- Class Property
weak var delegate: SegmentedHeaderDelegate?
//MARK:- Init Frame
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupAnchors()
}
//MARK:- TargetAction
@objc func selectedIndex(_ sender: UISegmentedControl){
let index = sender.selectedSegmentIndex
switch index {
case 0: // this means the first segment was chosen
delegate?.trackSelectedIndex(0)
break
case 1: // this means the middle segment was chosen
delegate?.trackSelectedIndex(1)
break
case 2: // this means the last segment was chosen
delegate?.trackSelectedIndex(2)
break
default:
break
}
}
fileprivate func setupAnchors(){
addSubview(segmentedControl)
segmentedControl.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
segmentedControl.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
segmentedControl.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
segmentedControl.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
在具有 UICollectionViewController 的 class 中:
重要 - 确保在 viewForSupplementaryElementOfKind 中设置委托,否则 none 将起作用
// MAKE SURE YOU INCLUDE THE SegmentedHeaderDelegate so the class conforms to it
class ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, SegmentedHeaderDelegate{
// add a class property for the header identifier
let segmentedHeaderIdentifier = "segmentedHeader"
// add a class property to keep track of which segment was selected. This gets set inside the tracktSelectedIndex() function. You will need this for cellForRowAtIndexPath so you can show whatever needs to be shown for each segment
var selectedSegment: Int?
// register the SegmentedHeader with the collectionView
collectionView.register(SegmentedHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: segmentedHeaderIdentifier)
// inside the collectionView's delegate below add the header
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var header: UICollectionReusableView?
if kind == UICollectionElementKindSectionHeader{
let segmentedHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: segmentedHeaderIdentifier, for: indexPath) as! SegmentedHeader
// IMPORTANT >>>>MAKE SURE YOU SET THE DELEGATE or NONE OF THIS WILL WORK<<<<
segmentedHeader.delegate = self
// when the scene first appears there won't be any segments chosen so if you want a default one to show until the user picks one then set it here
// for eg. when the scene first appears the last segment will show
segmentedHeader.segmentedControl.selectedSegmentIndex = 2
header = segmentedHeader
}
return header!
}
// inside cellForRowAtIndexPath check the selectedSegmented class property to find out which segment was chosen
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TheCell, for: indexPath) as! TheCell
// selectedSegment is the class property that gets set inside trackSelectedIndex()
switch selectedSegment {
case 0:
// have the cell display something for the first segment
break
case 1:
// have the cell display something for the middle segment
break
case 2:
// have the cell display something for the last segment
break
default:
break
}
return cell
}
// whenever a segment is selected, this delegate function will get passed the segment's index. It runs a switch statement on theSelectedIndex argument/parameter. Based on that result it will set the selectedIndex class property to match the value from theSelectedIndex argument/parameter
func trackSelectedIndex(_ theSelectedIndex: Int) {
switch theSelectedIndex {
case 0: // this means the first segment was chosen
// set the selectedSegment class property so you can use it inside cellForRowAtIndexPath
selectedSegment = 0
print("the selected segment is: \(theSelectedIndex)")
break
case 1: // this means the middle segment was chosen
selectedSegment = 1
print("the selected segment is: \(theSelectedIndex)")
break
case 2: // this means the last segment was chosen
selectedSegment = 2
print("the selected segment is: \(theSelectedIndex)")
break
default:
break
}
}
所以这个问题很简单。我有一个 UICollectionViewController
(MyProfile.swift)
和一个 header 部分 (MyProfileHeader.swift)
。在后者中,我有一个 UISegmentedControl
到 return 不同数量的项目和 collection view cells
中的项目(我不想在 class 中初始化后者的实例UICollectionViewController
)。这是我 MyProfile.swift class
的代码。我尝试在 viewForSupplementaryElementOfKind
方法中将目标添加到 return 不同的查询(有效),但我最终必须在 numberOfItemsInSection
和 cellForItemAtIndexPath
方法中访问分段控件。 "testObjects"
和 "writeObjects"
是 array
值,通过 viewForSupplementaryElementOfKind
中的 addTarget
方法查询。我设置了 indexPath
但它 returns
一个 error
出于显而易见的原因......我如何访问分段控制?
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
var numberOfItems: Int? = 0
let indexPath = NSIndexPath(forItem: 0, inSection: 0)
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "header", forIndexPath: indexPath) as! MyProfileHeader
if header.userContent.selectedSegmentIndex == 1 {
numberOfItems = textObjects.count
} else if header.userContent.selectedSegmentIndex == 2 {
numberOfItems = 0
} else {
numberOfItems = photoObjects.count
}
print("F: \(numberOfItems!)")
return numberOfItems!
}
当在 viewForSupplementaryElementOfKind
中为 collection 视图检索到 header 时,您可以在 MyProfile
中存储对它的弱引用。
class MyProfile: UICollectionViewController {
...
...
weak var header: MyProfileHeader?
...
...
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "header", forIndexPath: indexPath) as! MyProfileHeader
return header
}
然后您可以从 UICollectionViewController
中的任何其他功能访问它。
请注意,numberOfItemsInSection
和 cellForItemAtIndexPath
可以在 viewForSupplementaryElementOfKind
中创建 header 之前调用,因此当您在 numberOfItemsInSection
中访问它时, cellForItemAtIndexPath
,或您应该检查 null 的其他任何地方,然后假定分段控件处于默认值(因为这是第一次显示视图,所以它会是默认值)。像
let selectedSegmentIndex = header?.userContent.selectedSegmentIndex ?? 0 //0 is the default value here
-1st 创建一个 UICollectionReusableView
subclass 并将其命名为 SegmentedHeader
-2nd 在 SegmentedHeader class 中添加一个协议来跟踪选择了哪个段。当在 collectionView 的 header 中选择一个段时,protocol/delegate 将传递该段的值
-3rd 确保设置委托 weak var delegate: SegmentedHeaderDelegate?
-4th 在以编程方式创建 segmentedControl
时添加一个名为 selectedIndex(_ sender: UISegmentedControl) 的目标。当一个片段被按下时,你将该片段的值传递给协议 trackSelectedIndex() 函数
protocol SegmentedHeaderDelegate: class {
func trackSelectedIndex(_ theSelectedIndex: Int)
}
class SegmentedHeader: UICollectionReusableView {
//MARK:- Programmatic Objects
let segmentedControl: UISegmentedControl = {
let segmentedControl = UISegmentedControl(items: ["Zero", "One", "Two"])
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.tintColor = UIColor.red
segmentedControl.backgroundColor = .white
segmentedControl.isHighlighted = true
segmentedControl.addTarget(self, action: #selector(selectedIndex(_:)), for: .valueChanged)
return segmentedControl
}()
//MARK:- Class Property
weak var delegate: SegmentedHeaderDelegate?
//MARK:- Init Frame
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
setupAnchors()
}
//MARK:- TargetAction
@objc func selectedIndex(_ sender: UISegmentedControl){
let index = sender.selectedSegmentIndex
switch index {
case 0: // this means the first segment was chosen
delegate?.trackSelectedIndex(0)
break
case 1: // this means the middle segment was chosen
delegate?.trackSelectedIndex(1)
break
case 2: // this means the last segment was chosen
delegate?.trackSelectedIndex(2)
break
default:
break
}
}
fileprivate func setupAnchors(){
addSubview(segmentedControl)
segmentedControl.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
segmentedControl.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
segmentedControl.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
segmentedControl.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
在具有 UICollectionViewController 的 class 中:
重要 - 确保在 viewForSupplementaryElementOfKind 中设置委托,否则 none 将起作用
// MAKE SURE YOU INCLUDE THE SegmentedHeaderDelegate so the class conforms to it
class ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, SegmentedHeaderDelegate{
// add a class property for the header identifier
let segmentedHeaderIdentifier = "segmentedHeader"
// add a class property to keep track of which segment was selected. This gets set inside the tracktSelectedIndex() function. You will need this for cellForRowAtIndexPath so you can show whatever needs to be shown for each segment
var selectedSegment: Int?
// register the SegmentedHeader with the collectionView
collectionView.register(SegmentedHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: segmentedHeaderIdentifier)
// inside the collectionView's delegate below add the header
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var header: UICollectionReusableView?
if kind == UICollectionElementKindSectionHeader{
let segmentedHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: segmentedHeaderIdentifier, for: indexPath) as! SegmentedHeader
// IMPORTANT >>>>MAKE SURE YOU SET THE DELEGATE or NONE OF THIS WILL WORK<<<<
segmentedHeader.delegate = self
// when the scene first appears there won't be any segments chosen so if you want a default one to show until the user picks one then set it here
// for eg. when the scene first appears the last segment will show
segmentedHeader.segmentedControl.selectedSegmentIndex = 2
header = segmentedHeader
}
return header!
}
// inside cellForRowAtIndexPath check the selectedSegmented class property to find out which segment was chosen
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TheCell, for: indexPath) as! TheCell
// selectedSegment is the class property that gets set inside trackSelectedIndex()
switch selectedSegment {
case 0:
// have the cell display something for the first segment
break
case 1:
// have the cell display something for the middle segment
break
case 2:
// have the cell display something for the last segment
break
default:
break
}
return cell
}
// whenever a segment is selected, this delegate function will get passed the segment's index. It runs a switch statement on theSelectedIndex argument/parameter. Based on that result it will set the selectedIndex class property to match the value from theSelectedIndex argument/parameter
func trackSelectedIndex(_ theSelectedIndex: Int) {
switch theSelectedIndex {
case 0: // this means the first segment was chosen
// set the selectedSegment class property so you can use it inside cellForRowAtIndexPath
selectedSegment = 0
print("the selected segment is: \(theSelectedIndex)")
break
case 1: // this means the middle segment was chosen
selectedSegment = 1
print("the selected segment is: \(theSelectedIndex)")
break
case 2: // this means the last segment was chosen
selectedSegment = 2
print("the selected segment is: \(theSelectedIndex)")
break
default:
break
}
}