简体   繁体   English

如何在 UICollectionViewController 的标头中访问 UISegmentedControl?

[英]How can I access UISegmentedControl in header of UICollectionViewController?

So this problem is fairly straightforward.所以这个问题相当简单。 I have a UICollectionViewController (MyProfile.swift) with a header section (MyProfileHeader.swift) .我有一个UICollectionViewController (MyProfile.swift)具有报头部分(MyProfileHeader.swift) Within the latter, I have a UISegmentedControl to return different numbers of items AND items in the collection view cells (I don't want to initialize an instance of the latter's class within the UICollectionViewController ).在后者中,我有一个UISegmentedControl来返回collection view cells不同数量的项目和项目(我不想在UICollectionViewController初始化后者的类的UICollectionViewController )。 This is my code for MyProfile.swift class .这是我的MyProfile.swift class代码。 I tried adding a target in the viewForSupplementaryElementOfKind method to return different queries (which works), but I ultimately have to access the segmented control within the numberOfItemsInSection and cellForItemAtIndexPath methods.我尝试在viewForSupplementaryElementOfKind方法中添加一个目标来返回不同的查询(有效),但我最终必须访问numberOfItemsInSectioncellForItemAtIndexPath方法中的分段控件。 The "testObjects" and "writeObjects" are array values that are queried via the addTarget method in the viewForSupplementaryElementOfKind .所述"testObjects""writeObjects"array ,它们通过被查询值addTarget在该方法中viewForSupplementaryElementOfKind I set the indexPath but it returns an error for obvious reasons... How can I access segmented control?我设置了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!
}

-1st create a UICollectionReusableView subclass and name it SegmentedHeader UICollectionReusableView创建一个UICollectionReusableView子类并将其命名为SegmentedHeader

-2nd Inside the SegmentedHeader class add a protocol to keep track of which segment was selected. -2nd 在SegmentedHeader类中添加一个协议来跟踪选择了哪个段。 When a segment is selected inside the collectionView's header the protocol/delegate will get passed the value of that segment当在 collectionView 的标头中选择一个段时,协议/委托将传递该段的值

-3rd make sure you set the delegate weak var delegate: SegmentedHeaderDelegate? -3rd 确保您设置了委托weak var delegate: SegmentedHeaderDelegate?

-4th when programmatically creating the segmentedControl add a target named selectedIndex(_ sender: UISegmentedControl) . -4th 以编程方式创建segmentedControl添加一个名为selectedIndex(_ sender: UISegmentedControl) 的目标 When a segment is pressed, you pass the value of that segment to the protocols trackSelectedIndex() function当按下一个段时,您将该段的值传递给协议 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")
    }
}

Inside the class that has the UICollectionViewController:在具有 UICollectionViewController 的类中:

IMPORTANT - Make sure you set the delegate inside viewForSupplementaryElementOfKind or none of this will work重要 - 确保您在 viewForSupplementaryElementOfKind 中设置了委托,否则这些都不起作用

// 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
        }
}

When the header is retrieved for the collection view in viewForSupplementaryElementOfKind , you can store a weak reference to it in MyProfile .当在viewForSupplementaryElementOfKind为集合视图检索标头时,您可以在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
}

You can then access this from any other function in your UICollectionViewController .然后,您可以从UICollectionViewController任何其他函数访问它。

Note that numberOfItemsInSection and cellForItemAtIndexPath can be called before the header has been created in viewForSupplementaryElementOfKind , so when you access it in numberOfItemsInSection , cellForItemAtIndexPath , or anywhere else you should check for null and then assume that the segmented control is on the default value (as it will be since this is the first time the view is being displayed).请注意,可以在viewForSupplementaryElementOfKind创建标头之前调用numberOfItemsInSectioncellForItemAtIndexPath ,因此当您在numberOfItemsInSectioncellForItemAtIndexPath或其他任何地方访问它时,您应该检查空值,然后假设分段控件处于默认值(因为它将是因为这是第一次显示视图)。 Something like类似的东西

let selectedSegmentIndex = header?.userContent.selectedSegmentIndex ?? 0 //0 is the default value here

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将UISearchDisplayController与UICollectionViewController一起使用? - How can I use UISearchDisplayController with UICollectionViewController? 如何在UICollectionviewcontroller中显示文本字段? - How can I show the textfield in the UICollectionviewcontroller? 我可以通过编程方式重绘UISegmentedControl吗? 怎么样? - Can I redraw a UISegmentedControl programatically? How? 如何实现从UICollectionViewController到UIViewController的自定义UIViewController转换? - How can I achieve this custom UIViewController Transition from UICollectionViewController to UIViewController? 如何创建一个转接表单 UIViewController 到 UICollectionViewController? - 以编程方式 - How can I create a segue form UIViewController to UICollectionViewController ? - Programmatically 如何使用 UICollectionViewController 设置具有多个部分的 1 header - How to setup a 1 header with multiple sections using UICollectionViewController iOS:如何在UISegmentedControl中访问单个段? - iOS: How Do I Access Individual Segments in A UISegmentedControl? 我可以在一个应用程序中集成UIViewController和UICollectionViewController吗? - Can I integrate UIViewController and UICollectionViewController in one app? 如何在UISegmentedControl中为所选元素设置字体? - How can I set the font for the selected element in a UISegmentedControl? 如何使用RubyMotion将UISegmentedControl插入NavigationBar? - How can I insert a UISegmentedControl to a navigationBar using RubyMotion?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM