Анимация изменения текста заголовка навигационной панели

В моем приложении у меня есть контроллер просмотра страниц, который позволяет пользователю прокручивать между различными "разделами" приложения, а вверху - в панели навигации. Я меняю текст заголовка на новый раздел, который пользователь нажал через pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:. В настоящий момент он мгновенно меняет текст заголовка, когда анимация завершена. Я хотел бы улучшить это с помощью некоторой анимации, тонкого эффекта затухания и выхода.

Сначала я попытался реализовать [UIView animationWithDuration:...] для анимации изменения текста заголовка, но он не анимация и просто все еще мгновенно обновляется.

Затем я подумал, можно ли обновить альфа заголовка навигационной панели, когда пользователь прокручивает по горизонтали в зависимости от того, как далеко они прокручиваются, достигая 0 альфа, когда следующий раздел вот-вот появится на экране, затем Я могу мгновенно изменить текст, пока он равен 0, а затем быстро затухает до 1 альфа. Но я не вижу метод UIPageViewControllerDelegate, который вызывается при обновлении положения прокрутки.

Если возможно, вместо того, чтобы просто затухать и исчезать, я мог бы исчезать, а также перемещать текстовую позицию заголовка в навигационной панели, как и анимация по умолчанию, которая возникает при навигации по нажатию клавиши с помощью жестового салфетки. Я бы сместил старый заголовок раздела, когда пользователь прокручивает и предоставляет следующий заголовок раздела с другой стороны, так что, когда переход завершается, заголовок предыдущего раздела выключен, а новый полностью центрирован, поэтому замена завершается. Но опять же это требует знания точно, сколько пользователь прокрутил контроллер просмотра страницы.

Возможно ли реализовать любую из желаемых анимаций?

Ответ 1

Если вы хотите анимировать между различными строками заголовка, используйте следующее:

CATransition *fadeTextAnimation = [CATransition animation];
fadeTextAnimation.duration = 0.5;
fadeTextAnimation.type = kCATransitionFade;

[self.navigationController.navigationBar.layer addAnimation: fadeTextAnimation forKey: @"fadeText"];
self.navigationItem.title = "My new title";

Вы можете настроить продолжительность и установить функцию синхронизации, конечно.

Существуют и другие типы анимации, которые могут работать в разных обстоятельствах (спасибо @inorganik):

kCATransitionFade
kCATransitionMoveIn
kCATransitionPush
kCATransitionReveal

Ответ 2

Swift 5

let fadeTextAnimation = CATransition()
fadeTextAnimation.duration = 0.5
fadeTextAnimation.type = .fade

navigationController?.navigationBar.layer.add(fadeTextAnimation, forKey: "fadeText")
navigationItem.title = "test 123"

Для удобства решение Эшли Миллс в Swift:

16.11.2016 Обновлено для Swift 3 (спасибо n13)

let fadeTextAnimation = CATransition()
fadeTextAnimation.duration = 0.5
fadeTextAnimation.type = kCATransitionFade

navigationController?.navigationBar.layer.add(fadeTextAnimat‌​ion, forKey: "fadeText")
navigationItem.title = "test 123"

Swift 2.x

let fadeTextAnimation = CATransition()
fadeTextAnimation.duration = 0.5
fadeTextAnimation.type = kCATransitionFade

navigationController?.navigationBar.layer.addAnimation(fadeTextAnimation, forKey: "fadeText")
navigationItem.title = "test 123"

Я снимаю шляпу перед Эшли!

Ответ 3

Решение состоит в том, чтобы создать пользовательский заголовок и анимировать его позицию, используя скрытый метод делегирования прокрутки ViewView. Как сказал Чжан, пользовательское название просто self.navigationItem.titleView = customNavTitleLabel;

Ответ 4

Если вам нужно анимировать только заголовок (не всю панель навигации)

Разработать пользовательский контроль заголовка Ссылка, например

приписывать

  let titleView = UIAnimatedTitleView(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
 titleView.text = "Hello"

оживлять

var flag = true

@objc private func animateNavigationTitle() {
            guard let titleView = navigationItem.titleView as? UIAnimatedTitleView else { return }

        let fadeTextAnimation = CATransition()
        fadeTextAnimation.duration = 0.5
        fadeTextAnimation.type = kCATransitionPush
        fadeTextAnimation.subtype = kCATransitionFromTop

        titleView.layer.add(fadeTextAnimation, forKey: "pushText")
        titleView.text = flag ? "Hello" : "Good buy" 
        flag = !flag
    }

Ответ 5

Найден наилучший способ в этой категории:

@implementation UIViewController (ControllerNavigationEffects)

-(void) setNavigationTitleWithAnimation:(NSString *) title {
    if ([self.navigationItem.title isEqualToString:title]) {
        return;
    }
    @weakify(self);
    float duration = 0.2;
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        @strongify(self);
        self.navigationItem.titleView.alpha = 0;
    } completion:^(BOOL finished) {}];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        @strongify(self);
        self.navigationItem.titleView = nil;
        self.navigationItem.title = title;

        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.navigationItem.titleView.alpha = 1;
        } completion:nil];
    });
}

-(void) setNavigationTitleViewWithAnimation:(UIView *) titleView {
    if ([self.navigationItem.titleView isKindOfClass:[titleView class]]) {
        return;
    }
    @weakify(self);
    float duration = 0.2;

    CATransition *fadeTextAnimation = [CATransition animation];
    fadeTextAnimation.duration = duration;
    fadeTextAnimation.type = kCATransitionFade;

    [self.navigationController.navigationBar.layer addAnimation: fadeTextAnimation forKey: @"fadeText"];
    self.navigationItem.title = @"";


    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        @strongify(self);
        self.navigationItem.title = @"";
        self.navigationItem.titleView = titleView;

        [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.navigationItem.titleView.alpha = 1;
        } completion:nil];

    });
}