0

I tried to solve this problem since hours and didn't find a proper solution. I want to have a custom UICollectionView with a segmented control in the header. Changing the segmented control index should render the cells differently. So far I can display the segmented control in the header of my collectionView but changing the content of the collectionView inside of my UserSearchHeader doesn't work.

I created a custom UICollectionView called UserSearchController which is a Subclass of UICollectionView and conforms the UICollectionViewDelegateFlowLayout protocol.

        class UserSearchController: UICollectionViewController, 
              UICollectionViewDelegateFlowLayout, UISearchBarDelegate { ....

My custom collectionView UserSearchController has a custom header (UserSearchHeader) and custom cells (UserSearchCell).

  collectionView?.register(UserSearchCell.self, forCellWithReuseIdentifier: cellId)
  collectionView?.register(UserSearchHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerId")

The UserSearchHeader contains the segmented control.

   class UserSearchHeader: UICollectionViewCell {

var segmentedControl: UISegmentedControl = {
    let sc = UISegmentedControl(items: ["Username", "Hashtag"])
    sc.translatesAutoresizingMaskIntoConstraints = false
    sc.tintColor = UIColor.black
    sc.selectedSegmentIndex = 0 // automatically highlight
    //  sc.addTarget(self, action: #selector(segmentedChange), for: .valueChanged)
    return sc
}() .....

If the segmentedIndex is 0 I want to render the cells with the UserSearchCell class if the segmentedIndex is 1 I want to render it with a different cellClass (Clicking the segmented control). How can I achieve this behavior with these different classes. shall I use the cellForItem at method inside of the UserSearchController to check the status of the segmented control. But how can I do this when the segmented control is defined in the UserSearchHeader class .

       override func collectionView(_ collectionView: 
    UICollectionView, cellForItemAt indexPath: IndexPath) -> 
  UICollect. ionViewCell { if segmentedControl.segmentedIndex = 0 ....}
Developer Omari
  • 434
  • 5
  • 14
  • Yes you can easily perform that , after changing selected index you need to reload your collection view, and in you cellforrow at index path check if selected index is zero return cell1 and if selected index is 1 return cell2 – Matloob Hasnain May 24 '17 at 09:39
  • 1
    I tried this but this doesn't work because segmentedControl is defined in the UserSearchHeader. The content doesn't change because the targetAction of the segmented control is not executed – Developer Omari May 24 '17 at 09:39
  • OK then make protocol that notify you once selected index change and also pass you selected index as well. – Matloob Hasnain May 24 '17 at 09:41
  • Thanks, But I don't know how to do that, Can you give me a short example based on my classes it would help me a lot . – Developer Omari May 24 '17 at 09:42
  • ok send me code i will do that if you can – Matloob Hasnain May 24 '17 at 09:59
  • the way you react to a scopeButton being pressed is through the `searchBar:selectedScopeButtonIndexDidChange:` method in the `UISearchBarDelegate` like described in my answer below. – pesch May 24 '17 at 10:45

1 Answers1

0

tried using Use the scopeButtonTitles property?

mySearchController.searchBar.scopeButtonTitles = ["Username", "Hashtag"]

Have a look at this question for more details. Basically you use the

func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { 
    // respond to your scopeBar selection here
    switch selectedScope {
    case 0:
        print("Username tab selected")
        // do your stuff for Username here
    case 1:
        print("Hashtag tab selected")
        // do your stuff for Hashtag here
    default:
        print("Someone added a tab!")
        // you shouldn't have more than 2 tabs
}

EDIT: Please find below the missing pieces described in the link provided initially. There is no need to add the header from a NIB.

First, you add properties for your search & results controllers:

typealias ResultVC = UserResultController //The class to show your results
var searchController: UISearchController! 
var resultController: ResultVC? 

Then, in viewDidLoad you add this:

// Search Results 
resultController = ResultVC() 
setupSearchControllerWith(resultController!) 
if #available(iOS 9.0, *) { 
    searchController?.loadViewIfNeeded() 
} 

Then you need to add this function to your class:

func setupSearchControllerWith(_ results: ResultVC) { 
    // Register Cells 
    results.tableView.register(TableCell.self, forCellReuseIdentifier: "\(TableCell.self)") 
    results.tableView.register(UINib(nibName: "\(TableCell.self)", bundle: Bundle.main), forCellReuseIdentifier: "\(TableCell.self)") 

  // We want to be the delegate for our filtered table so didSelectRowAtIndexPath(_:) is called for both tables. 
    results.tableView.delegate = self 

    searchController = UISearchController(searchResultsController: results) 

    // Set Scope Bar Buttons 
    searchController.searchBar.scopeButtonTitles = ["Comics only", "Digital too"] 

    // Set Search Bar 
    searchController.searchResultsUpdater = self 
    searchController.searchBar.sizeToFit() 
    tableView.tableHeaderView = searchController.searchBar 

    // Set delegates 
    searchController.delegate = self 
    searchController.searchBar.delegate = self    // so we can monitor text & scope changes 

    // Configure Interface 
    searchController.dimsBackgroundDuringPresentation = false 
    searchController.hidesNavigationBarDuringPresentation = true 
    if #available(iOS 9.1, *) { 
        searchController.obscuresBackgroundDuringPresentation = false 
    }  

    // Search is now just presenting a view controller. As such, normal view controller 
    // presentation semantics apply. Namely that presentation will walk up the view controller 
    // hierarchy until it finds the root view controller or one that defines a presentation context. 
    definesPresentationContext = true 
} 

Finally, you add the function I was describing initially: searchBar:selectedScopeButtonIndexDidChange:

pesch
  • 1,976
  • 2
  • 17
  • 29
  • My searchBar is inside my navigationBar and when adding the property scopeButtonTitles its not showing anything just a gray background – Developer Omari May 24 '17 at 15:27
  • If I put the searchbar into the header of my collectionView it is again in another class and I don't have access. How can I show the searchBar wit scopeButtonTiles inside of the navigationBar. How can we increase the height of the navigationBar automatically ? – Developer Omari May 24 '17 at 15:42
  • Check the property for your UISearchController. In my example it's called mySearchController. As you can see, the searchBar property is a property of your navigationBar. Have a look at the property name of your UISearchController and also the way you add your searchBar. In the link provided you have an example. Have a look since adding the searchBar is a one-liner too. – pesch May 24 '17 at 15:47
  • No its not working see: https://stackoverflow.com/questions/44164324/how-to-add-a-searchbar-with-scopebar-inside-of-a-navigationbar-where-the-navbar. How can I solve it with segmented Control. – Developer Omari May 24 '17 at 17:32