uias / Pageboy

📖 A simple, highly informative page view controller
MIT License
1.99k stars 155 forks source link

iOS 11 Large titles #122

Open axmav opened 7 years ago

axmav commented 7 years ago

Hello!

When using: self.navigationController?.navigationBar.prefersLargeTitles = true in TabViewController, and UITableViewControllers as viewControllers - everything OK, but navigation not collapsing when i scroll tableview. How to connect scrolling with LargeNavigation?

Should be: ezgif com-video-to-gif 5

farshadmb commented 7 years ago

This issue is ios 11 Bug. use this code self.navigationItem.largeTitleDisplayMode = .never self.navigationItem.largeTitleDisplayMode = .automatic

and you see the Magic @Mazorati

axmav commented 7 years ago

@farshadmb thanks for your reply. If you think that i cant use google with first solution - you make mistake. Still not working. I suppose that UILargeNavigationItem requires uiscrollview as superview. i upload code: https://github.com/Mazorati/test8/blob/master/test8/Test2ViewController.swift

farshadmb commented 7 years ago

@Mazorati. Ok, I will check it out. thanks for provide a code

msaps commented 7 years ago

@Mazorati @farshadmb I think this is an issue related to how UIKit internally handles the transitioning of the nav bar titles and the hierarchy that Pageboy uses.

Basic VC hierarchy:

PageboyViewController
     -> UIPageViewController
          -> [ChildViewControllers]

UINavigationController obviously hooks into any scroll view that is present in the visible view controller and uses it to transition the bar, so I'm not sure if there is any way to manually point to a UIScrollView for this, or whether we can get the navigation controller to find the child view controller scroll view.

Will need some investigation...

jnshey commented 6 years ago

Does Pageboy work with UINavigationBar.prefersLargeTitles in iOS 11? Thanks a lot.

msaps commented 6 years ago

@jnshey I haven't had chance to investigate the above mentioned bug any further as of yet, so I'm not sure how well Pageboy works with the large titles. Will prioritise it to look at ASAP. 👍

msaps commented 6 years ago

@Mazorati @jnshey as suspected I don't think this will be possible due to the way that it's implemented in iOS. 😢

UINavigationController apparently only looks at the first subview in the child view controller for whether to respond to UIScrollView events. With Pageboy the scroll view is a few child levels deeper:

-> UINavigationController
     -> PageboyViewController
          -> UIPageViewController (UIKit will be looking here for the scroll view)
               -> YourChildViewController
                    -> YourScrollView 

I can't seem to see any real solution on the dev forums or online unfortunately - the best people have come up with is changing the large title mode in an animation block: Stack Overflow

jnshey commented 6 years ago

@msaps Will it be possible if one wraps the PageboyViewController's view in a giant UIScrollView?

Like this:

UINavgationController
  -> ChildViewController (whose first subview is a UIScrollView that contains PageboyViewController's main view)
vanab commented 6 years ago

Hi! Bad but working method: Add UIScrollView to PageBoyViewController. Important - UIScrollView must have index 0. (see here) In YourScrollView we can use scrollViewDidScroll and set offset on our "main" UIScrollView.

upd: Its work. At least in Tabman gif

msaps commented 6 years ago

@vanab looks interesting! Would you be able to post your view hierarchy so we can get a better look?

vanab commented 6 years ago

@msaps this TabmanViewController. UIScrollView at index 0(this is important).

2018-03-04 18 10 44 image

and in all childViewcontrollers

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if #available(iOS 11.0, *) {
                let offset = scrollView.contentOffset
                tabmanVC.scrollView.contentOffset = offset
          }
}
msaps commented 6 years ago

@vanab ah perfect thank you! I've done a little demo project which uses your methods - seems to work great:

Pageboy-NavCollapse.zip

Will try and get this integrated into Pageboy so that it provides support for this natively 🙏

gaojinhsu commented 6 years ago

@msaps your demo works fine but not smoothly enough. I can't figure out why. @vanab can you provide your demo please? My case also has a tab bar, and I hope the large title navigation bar in your demo shrinks as smoothly as system's.

vanab commented 6 years ago

@gaojinhsu hmmmm. Looks like iOS 11.3 problem. See my gif here . Now it no work too

wow-such-amazing commented 6 years ago

any updates for iOS 11.3 or 11.4? I think there is the same problem on iOS 11.4

gaojinhsu commented 6 years ago

@vanab There must be some ways. At least, I've seen some apps make it. https://itunes.apple.com/cn/app/yuan-fu-dao-chu-gao-zhong/id974568444?mt=8

vanab commented 6 years ago

@gaojinhsu i have no idea. in your app nav bar not resizing. pull-to-refresh not conform iOS 11 guidelines. it should be inside navbar, not headerView

Vortec4800 commented 6 years ago

Is this still in progress?

msaps commented 6 years ago

@Vortec4800 yeah sorry it is - working on it as part of Pageboy 3.0. Also rebuilding Tabman for 2.0 so got quite a lot going on! 😄

Vortec4800 commented 6 years ago

Well we use Pageboy and Tabman for various things, so we'll be grateful for both.

Do you have an ETA on 3.0? We've got a project that's scheduled for release early August and it would be nice to have the large titles working in it. If not, perhaps I could work in a workaround for the time being.

msaps commented 6 years ago

@Vortec4800 unfortunately no ETA just yet. Though the Pageboy release is a lot more iterative than Tabman, so hopefully can get that out a little quicker.

Will endeavour to prioritise getting something sorted for the large title issue in 11.3+

Vortec4800 commented 6 years ago

No problem. Thanks for all the work on this!

msaps commented 6 years ago

Unfortunately didn't make much more progress with this after the issue that arose in iOS 11.3. I've removed it from (just released) Pageboy 3.

I have kept the feature/large-nav-title-support branch open with the changes, now up to date with master. So I wouldn't say this is completely dead, just unfortunately couldn't figure it out just yet 😢

junaidxabd commented 5 years ago

I tried using this library to collapse the title bar but still no luck https://github.com/andreamazz/AMScrollingNavbar

junaidxabd commented 5 years ago

Is there a way to collapse the tab bar though?

sonrier commented 5 years ago

worked in this way func scrollViewDidScroll(_ scrollView: UIScrollView) { if #available(iOS 11.0, *) { let offset = scrollView.contentOffset tabmanVC.scrollView.contentOffset = offset tabmanVC.scrollView.panGestureRecognizer.state = scrollView.panGestureRecognizer.state } }

sunnysidevibes commented 5 years ago

@sonrier where would i override scrollViewDidScroll ?

wx0165927473 commented 4 years ago

Hey @vanab @sonrier, just found this and I tried the exact same way. Didn't work on 13.2.2. Did you try recently? Or is there any other ways to do the hack here? Thanks

tiarnann commented 4 years ago

I am trying this on iOS 13.1. And I get this to work but it is very choppy. Has anyone iterated on this or found an alternative?

brunohenriquesk1 commented 4 years ago

No luck so far, maybe creating a tableView then adding the pageViewController inside the tableViewCell?

brunohenriquesk1 commented 4 years ago

Ok, I not using this framework but I'm trying to archive the same animation with the native PageViewController. I was able to make it in a smooth way by nesting a PageViewController inside a tableview cell. You'll have to set scrolling to disabled on the tableView inside your PageViewController.

kiritokatklian commented 3 years ago

worked in this way func scrollViewDidScroll(_ scrollView: UIScrollView) { if #available(iOS 11.0, *) { let offset = scrollView.contentOffset tabmanVC.scrollView.contentOffset = offset tabmanVC.scrollView.panGestureRecognizer.state = scrollView.panGestureRecognizer.state } }

For iOS 15 (and I assume 14 as well), going off this solution I also assigned some other properties which helped make the scrolling smoother. Basically, the more properties you assign the better the scrolling experience becomes. Unfortunately assigning scrollView itself to tabmanVC.scrollView does nothing, so you have to assign the properties one for one.

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if let parent = self.parent?.parent as? TabmanViewController {
        parent.scrollView.contentSize = scrollView.contentSize
        parent.scrollView.contentInset = scrollView.contentInset
        parent.scrollView.contentOffset = scrollView.contentOffset
        parent.scrollView.decelerationRate = scrollView.decelerationRate
        parent.scrollView.panGestureRecognizer.state = scrollView.panGestureRecognizer.state
        parent.scrollView.directionalPressGestureRecognizer.state = scrollView.directionalPressGestureRecognizer.state
    }
}
danfixeads commented 3 years ago

@kiritokatklian Hello, how did you get it to work? I keep getting an error about the scrollview being private

'scrollView' is inaccessible due to 'private' protection level

kiritokatklian commented 3 years ago

@danfixeads sorry for the late reply. You need to replace the TabmanViewController with your own subclass which will contain the scrollView.

So following this example from the comment above, you will need to add a scrollView to your subclass of TabmanViewController and have it at index 0. I did this using storyboard so this is my class.

class FirstViewController: TabmanViewController {
    // MARK: - IBOutlets
    @IBOutlet weak var scrollView: UIScrollView! // 

    // Some code...
}

In the storyboard, I have a scrollView as the only view, so it's the first view by default. If you're doing this step programmatically then put the scrollView behind all other views.

The second class is a collection view controller which already implements UIScrollViewDelegate, so in my case:

class SecondViewController: UICollectionViewController {
    // Some code...
}

// MARK: - UIScrollViewDelegate
extension SecondViewController {
    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if let parent = self.parent?.parent as? FirstViewController {
            parent.scrollView.contentSize = scrollView.contentSize
            parent.scrollView.contentInset = scrollView.contentInset
            parent.scrollView.contentOffset = scrollView.contentOffset
            parent.scrollView.decelerationRate = scrollView.decelerationRate
            parent.scrollView.panGestureRecognizer.state = scrollView.panGestureRecognizer.state
            parent.scrollView.directionalPressGestureRecognizer.state = scrollView.directionalPressGestureRecognizer.state
        }
    }
}

Now you won't get the inaccessible error.