andreamazz / AMScrollingNavbar

Scrollable UINavigationBar that follows the scrolling of a UIScrollView
MIT License
6.05k stars 634 forks source link

search controller on ios 11 #296

Open fralways opened 6 years ago

fralways commented 6 years ago

Hi, I have an issue with navigation + search controller on ios11. If I scroll slowly my table view it can happen that search bar doesnt behave as intended-

ex1: I scroll up just a bit more than a half of nav bar height, then release - nav bar gets removed, but parts of search bar remains.

ex2: I scroll very little up, then release - nav bar gets reseted to original height, but search bar now has less height then when I started to scroll. (It doesnt help if I add self.searchController.searchBar as follower)

Any1 else with these issues? Im using objc. For test purpose you could add property - @property UISearchController *searchController; method in viewDidLoad - [self initSearchController] and implementation -

- (void)initSearchController{
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.hidesNavigationBarDuringPresentation = NO;
    self.searchController.searchBar.searchBarStyle = UISearchBarStyleDefault;
    self.searchController.searchBar.placeholder = @"search";

    if (@available(iOS 11.0, *)) {
        self.navigationItem.searchController = self.searchController;
    }else{
        self.navigationItem.titleView = self.searchController.searchBar;
    }
}
andreamazz commented 6 years ago

This is being discussed in #219 I don't have a fix unfortunately, any help is welcome.

fralways commented 6 years ago

Ok so after spending a bit of time here, the idea is to prevent scrolling navbar if search bar is visible. What I did is next in ScrollingNavigationController - added property fileprivate var searchController: UISearchController?

added methods:

private func checkSearchController(_ delta: CGFloat) -> Bool {
        if searchController != nil && delta > 0 {
            if searchController!.searchBar.frame.height != 0 {
                return false
            }
        }
        return true
    }
open func followScrollView(_ scrollableView: UIView, delay: Double = 0, scrollSpeedFactor: Double = 1, followers: [UIView] = [], searchController: UISearchController) {
        self.searchController = searchController
        followScrollView(scrollableView, delay: delay, scrollSpeedFactor: scrollSpeedFactor, followers: followers)
    }

(note: I added a complete new method, other solution would be to include searchbar in followers, and then check if any of followers is searchbar)

and last edited method -

func handlePan(_ gesture: UIPanGestureRecognizer) {
        if let superview = scrollableView?.superview {
            let translation = gesture.translation(in: superview)
            let delta = (lastContentOffset - translation.y) / scrollSpeedFactor
            if (!checkSearchController(delta)){
                lastContentOffset = translation.y
                return
            }

            if gesture.state != .failed {
                lastContentOffset = translation.y
                if shouldScrollWithDelta(delta) {
                    scrollWithDelta(delta)
                }
            }
        }

        if gesture.state == .ended || gesture.state == .cancelled || gesture.state == .failed {
            checkForPartialScroll()
            lastContentOffset = 0
        }
    }

And, of course, the call now is [((ScrollingNavigationController *)self.navigationController) followScrollView:self.tableView delay:0 scrollSpeedFactor:1 followers:@[] searchController:self.searchController];

Could you check this out?

andreamazz commented 6 years ago

That looks good, I'm just wondering if we can just check for topViewController?.navigationItem.searchController instead. That should work, right?

andreamazz commented 6 years ago

Ok, that seems to work, checkout commit 1123b4e

fralways commented 6 years ago

Just found out there could be setting self.navigationItem.hidesSearchBarWhenScrolling = false; in this case fix doesnt work and quick solution might be to just ignore new code (checkSearchController method returns true in this case), but graphics is very buggy.