Transition Navigation Bar Title

寵の児 提交于 2019-12-03 07:21:22

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.

Breno Morais

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!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!