In an app called "Luvocracy" the title of the navigation bar is changed when the user swipes up on the screen. The old title is pushed up, while the new one is transitioned in. I don't have a video of it now, but here are some screen shots:
https://www.dropbox.com/s/sns0bsxkdv7pw3l/Photo%20Apr%2008%2C%2011%2001%2005%20AM.png
https://www.dropbox.com/s/ys9a49u3dyxrlcm/Photo%20Apr%2008%2C%2011%2001%2009%20AM.png
https://www.dropbox.com/s/dlcfvfvqqov3ag7/Photo%20Apr%2008%2C%2011%2001%2013%20AM.png
How can I animate or transition in a new navigation bar title as shown?
Edit: The app is no longer available on the app store so I am unable to upload a video of this action.
You can animate the title changing by using a CATransition... however, because the title itself is a private property on the navigation bar, you need to first create a custom label and attach that to the navigation item.
Setup the title label (this would override the default navigation bar's title):
UILabel *titleLabelView = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 44.0f) /* auto-sized anyway */];
titleLabelView.backgroundColor = [UIColor clearColor];
titleLabelView.textAlignment = NSTextAlignmentCenter;
titleLabelView.textColor = [UIColor blackColor];
titleLabelView.font = [UIFont systemFontOfSize:16.0f];
titleLabelView.adjustsFontSizeToFitWidth = YES;
titleLabelView.text = @"@cracy123";
self.navigationItem.titleView = titleLabelView;
Then whenever you want to animate the title changing (assume on a scroll view delegate action), add a CAAnimation layer and presto:
CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.type = kCATransitionPush;
animation.subtype = kCATransitionFromTop;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.navigationItem.titleView.layer addAnimation:animation forKey:@"changeTitle"];
((UILabel*)self.navigationItem.titleView).text = @"JACOB K";
You can obviously change the CATransition animation properties to get the effect you're after, but those will give you the 'push-up' effect.
Just because a Swift answer was missing, here's the Swift implementation of Gavin's answer:
Setting up the custom title label:
let titleLabelView = UILabel.init(frame: CGRect(x: 0, y: 0, width: 0, height: 44))
titleLabelView.backgroundColor = UIColor.clearColor()
titleLabelView.textAlignment = .Center
// this next line picks up the UINavBar tint color instead of fixing it to a particular one as in Gavin's solution
titleLabelView.textColor = UINavigationBar.appearance().tintColor
titleLabelView.font = UIFont.boldSystemFontOfSize(16.0)
titleLabelView.text = "Old Title"
self.navigationItem.titleView = titleLabelView
And here's the title animation code:
let titleAnimation = CATransition()
titleAnimation.duration = 0.5
titleAnimation.type = kCATransitionPush
titleAnimation.subtype = kCATransitionFromTop
titleAnimation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
navigationItem.titleView!.layer.addAnimation(titleAnimation, forKey: "changeTitle")
(navigationItem.titleView as! UILabel).text = "New Title"
// I added this to autosize the title after setting new text
(navigationItem.titleView as! UILabel).sizeToFit()
This was a great answer but it took some tweaking for me to get it right.
So the general idea is that you have a text in the middle of your scrollView and when the user scrolls up past that text then you want it to become the new title. Furthermore, when you scroll back down, you want it to change back to the default title.
So, using the code that Gix posted, now converted to Swift 3, here's how you get it done.
Add these variables to the top of your viewController
var didChangeTitle = false
let defaultTitle = "Default Title"
let animateUp: CATransition = {
let animation = CATransition()
animation.duration = 0.5
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromTop
animation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
return animation
}()
let animateDown: CATransition = {
let animation = CATransition()
animation.duration = 0.5
animation.type = kCATransitionPush
animation.subtype = kCATransitionFromBottom
animation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
return animation
}()
In your viewDidLoad, add this code to set the default title.
let titleLabelView = UILabel.init(frame: CGRect(x: 0, y: 0, width: 200, height: 44))
titleLabelView.backgroundColor = .clear
titleLabelView.textAlignment = .center
titleLabelView.textColor = UINavigationBar.appearance().tintColor
titleLabelView.font = UIFont.boldSystemFont(ofSize: 16)
titleLabelView.text = defaultTitle
self.navigationItem.titleView = titleLabelView
Now you add some code to your scrollView delegate function:
extension MyViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y >= (labelName.frame.origin.y + labelName.frame.height) && !didChangeTitle {
if let label = navigationItem.titleView as? UILabel {
label.layer.add(animateUp, forKey: "changeTitle")
label.text = labelName.text
}
didChangeTitle = true
} else if scrollView.contentOffset.y < labelName.frame.origin.y && didChangeTitle {
if let label = navigationItem.titleView as? UILabel {
label.layer.add(animateDown, forKey: "changeTitle")
label.text = defaultTitle
}
didChangeTitle = false
}
}
}
The "labelName" var is the label in your scrollview that contains your future title.
This is an example:
UILabel *titleLabelView = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f) /* auto-sized anyway */];
titleLabelView.backgroundColor = [UIColor clearColor];
titleLabelView.textAlignment = NSTextAlignmentCenter;
(and others applications)
self.navigationItem.titleView = LabelView;
I don't understand very well your question!