質問

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.

enter image description here

他のヒント

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.

enter image description here

enter image description here

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!

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top