2

I'm attempting to put a collection view within the navigation bar, as seen in iMessage group chats where all members have their initials in circles in the nav bar.

I found an answer here on SO and I did my best to convert it to iOS10/Swift 3, but the collection view cells are not showing up in the nav bar correctly. Here's my code:

import UIKit


weak var collectionView: UICollectionView?

class ChatController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

override func viewDidLoad() {
    super.viewDidLoad()

    let layout = UICollectionViewFlowLayout()
    let collectionView = UICollectionView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(300), height: CGFloat(80)), collectionViewLayout: layout)
    collectionView.backgroundColor = UIColor.clear
    navigationItem.titleView? = collectionView
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
    collectionView.delegate? = self
    collectionView.dataSource? = self
    view.addSubview(collectionView)
    collectionView.reloadData()
}


func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 5
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = (collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) )
    cell.backgroundColor = UIColor.orange
    cell.layer.cornerRadius = 24
    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: CGFloat(50), height: CGFloat(50))
}

}

And the Navigation Bar class:

import Foundation
import UIKit



class NavigationBar: UINavigationBar {

var chatController: ChatController?

override func sizeThatFits(_ size: CGSize) -> CGSize {
    return CGSize(width: CGFloat(self.superview!.bounds.size.width), height: CGFloat(80))
}

func setFrame(frame: CGRect) {
    var f = frame
    f.size.height = 80
    super.frame = f
}


}

It looks like the collection view cells are showing up, but they're below the nav bar instead of inside it (see below image). If I hide the nav bar the cells go to the top of the view, but I want to have them within the nav bar.

enter image description here

Here's my UI code in app delegate, not sure if I'm making a newbie mistake here:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    window = UIWindow(frame: UIScreen.main.bounds)
    window?.makeKeyAndVisible()
    window?.rootViewController = UINavigationController(rootViewController: ChatController())

    return true
}

I'm doing this programmatically (no storyboard). Can anyone see where I'm going wrong?

Community
  • 1
  • 1
KingTim
  • 1,281
  • 4
  • 21
  • 29
  • call `view.addSubview(collectionView) collectionView.reloadData()` as last call in `viewDidLoad`. Post the code where you add your navigationBar. – shallowThought Dec 04 '16 at 21:54
  • Thanks, I forgot to add the subview.. unfortunately that doesn't fix it though! Still just a plain view controller/nav bar. – KingTim Dec 04 '16 at 22:00
  • Show how you add ChatController. – shallowThought Dec 04 '16 at 22:15
  • Add the collection view to the title-view in the navigation bar – JoakimE Dec 04 '16 at 22:22
  • Forgive me since I'm very new and this is my first time doing an interface programmatically, but aren't I doing that with this line navigationItem.titleView = collectionView – KingTim Dec 04 '16 at 22:30

1 Answers1

3

Here is my proposed solution

From Apple

If you want to display custom views in the navigation bar, you must wrap those views inside a UIBarButtonItem object before adding them to the navigation item.

For information about how navigation items work together with a navigation controller, custom view controllers, and the navigation bar to display their content, see View Controller Programming Guide for iOS.

weak var collectionView: UICollectionView?
override func viewDidLoad() {
    super.viewDidLoad()
    let navigationitem = UINavigationItem(title: "")    //creates a new item with no title
    navigationitem.titleView = collectionView //your collectionview here to display as a view instead of the title that is usually there
    self.navigationController?.navigationBar.items = [navigationitem] //adds the navigation item to the navigationbar
}

From the documentation I believe this should work. Remember to have your collection view cells small enough to fit in the navigation bar. Let me know if it doesn't work, maybe I can work something out tomorrow.

JoakimE
  • 1,820
  • 1
  • 21
  • 30
  • That's really interesting, I didn't realize you had to wrap the view in a bar button item, I'll do some more reading... interesting though because the example I referenced in my OP (the other answer on SO in obj-c) worked fine without doing that. I tried your code and unfortunately got a crash, here's the error: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot call setItems:animated: directly on a UINavigationBar managed by a controller.' – KingTim Dec 04 '16 at 23:37
  • Google that error and you will find the solution immediately. – Son of a Beach Dec 06 '16 at 03:50
  • Can you share which result got it working for you? I googled the error and tried the solutions on the first page of results, and the issue still persists. – KingTim Dec 06 '16 at 05:54