iossearchchatcustomizingjsqmessagesviewcontroller

How to add a searchbar to JSQMessagesViewController


In my chat application I am using JSQMessagesViewController for rendering the conversation. The application also has public messages that I want to search in. I am now trying to display them using JSQMessagesViewController. For this I want to hide the inputToolbar (that works) and add a search bar.

How do I make the searchbar visible? When you look at the property topContentAdditionalInset it looks like that it should be possible. Here is my code with my attempts:

override func viewDidLoad() {
    super.viewDidLoad()

    self.inputToolbar.removeFromSuperview()

    self.searchBar.removeFromSuperview()
    self.topContentAdditionalInset = 44
    self.searchBar.frame = CGRect(x: 0, y: 25, width: 320, height: 44)

    // Attempt 1
    // self.collectionView.addSubview(self.searchBar)

    // Attempt 2
    // self.view.addSubview(self.searchBar)

    // Attempt 3
    // self.navigationController?.navigationBar.addSubview(self.searchBar)

    // Attempt 4
    // self.inputToolbar.addSubview(self.searchBar)

    // Attempt 5
    self.collectionView.superview!.addSubview(self.searchBar)
}

Update:

The following code seems to work reasonably OK. The issues with it are: - It's a child of the collectionView and therefore will scroll with the content out of sight. Adding it to the .superview does not work. - it scrolls down 44 pixels when the searchbar gets focus.

var keepRef:JSQMessagesInputToolbar!
var searchBar:UISearchBar!
override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    if self.inputToolbar.superview != nil {
        keepRef = self.inputToolbar
        self.inputToolbar.removeFromSuperview()
    }

    self.topContentAdditionalInset = 44
    if searchBar == nil {
        searchBar = UISearchBar(frame: CGRect(x: 0, y: -44, width: 320, height: 44))
        searchBar.delegate = self
        self.collectionView.scrollsToTop = true
        self.collectionView.addSubview(searchBar)
    }
    self.filterContentForSearchText("")
}

Update 2:

Based on Sergey's answer (which works) I am now using the following code:

var keepRef:JSQMessagesInputToolbar!
var searchBar:UISearchBar!
override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.inputToolbar.hidden = true
    self.topContentAdditionalInset = 44
    self.collectionView.scrollsToTop = true
    if searchBar == nil {
        searchBar = UISearchBar()
        searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)
        searchBar.delegate = self
        self.view.addSubview(searchBar)

        let views = ["searchBar" : self.searchBar];
        searchBar.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("[searchBar(44)]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[searchBar]|", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
        self.view.addConstraint(NSLayoutConstraint(item: searchBar, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1.0, constant: 0.0))
    }
    self.filterContentForSearchText("")
}

Solution

  • First of all: JSQMessagesViewController subclass of UIViweController. This means that you can easily add subviews. You almost done all correctly in Attempt 2 but you set incorrect frame. I suggest you to use auto layout for this as in code below:

    Swift

    var searchBar: UISearchBar!;
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        searchBar = UISearchBar()
        searchBar.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.addSubview(searchBar)
    
        let views = ["searchBar" : self.searchBar];
    
        searchBar.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("[searchBar(44)]", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
    
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[searchBar]|", options: NSLayoutFormatOptions(0), metrics: nil, views: views))
    
        self.view.addConstraint(NSLayoutConstraint(item: searchBar, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1.0, constant: 0.0))
    }
    

    Objective C

    @property (nonatomic, strong) UISearchBar *searchBar;
    ...
    // viewDidLoad
    
    self.searchBar = [UISearchBar new];
    self.searchBar.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.searchBar];
    
    NSDictionary *views = @{@"searchBar" : self.searchBar};
    
    [self.searchBar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[searchBar(44)]"
                                                                           options:0
                                                                           metrics:nil
                                                                             views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[searchBar]|"
                                                                      options:0
                                                                      metrics:nil
                                                                        views:views]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.searchBar
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.topLayoutGuide
                                                          attribute:NSLayoutAttributeBottom
                                                         multiplier:1.0
                                                           constant:0.0]];