Анимировать изменение текста заголовка в Navigation Controller - PullRequest
2 голосов
/ 30 апреля 2019

Я пытаюсь оживить изменение заголовка детали UITableViewController, которая встроена в UINavigationController.

Эти два вопроса и ответов при переполнении стека кажутся наиболее актуальными ...

Я попробовал несколько вариантов кода, в основном, следуя Эшли Миллсу ответ и другим, основываясь на его ответе, но, по сути, я не могу заставить анимацию работать!

Запись заметок в Swift5 с использованием Xcode 10.2.

Я использую настройку Master-Detail UITableViewController для управления списком и деталями элементов в этом списке.

Я использую большие заголовки...

navigationController?.navigationBar.prefersLargeTitles = true

... и контроллер поиска ...

navigationItem.searchController = <<mySearchController>>
navigationItem.hidesSearchBarWhenScrolling = false
definesPresentationContext = true

... все установлено в методе viewDidLoad() для Master View Controller.

Вот что я сделал.

В моем проекте:

  1. import Framework QuartzCore, согласно комментарию Джека Бэлаlis «вам нужно добавить платформу QuartzCore через [проект]> [цель]> фазы сборки> двоичные файлы ссылок> QuartzCore.framework.";

    В контроллере основного вида:

  2. import QuartzCore;

    В контроллере подробного представления:

  3. В методе viewDidAppear(_ animated: Bool) введите код CATransition, аналогичныйответы на описанный выше OP (который изменяет Большой заголовок, но без анимации).

    override func viewDidAppear(_ animated: Bool) {
    
        super.viewDidAppear(animated)
    
        let animationTransition = CATransition()
    
        animationTransition.duration = 2.0
    
        animationTransition.type = CATransitionType.push
        animationTransition.subtype = CATransitionSubtype.fromTop
    
        navigationController!.navigationBar.layer.add(animationTransition, forKey: "pushText")
    
        navigationItem.title = <<NEW TITLE TEXT>>
    }
    
  4. В методе viewDidAppear(_ animated: Bool) напишите альтернативы коду CATransition, предложенному вответы на OP, отмеченные выше (который только добавляет отдельный заголовок в центр панели навигации и не меняет большого заголовка).

    override func viewDidAppear(_ animated: Bool) {
    
        super.viewDidAppear(animated)
    
        let animationTransition = CATransition()
    
        animationTransition.duration = 2.0
    
        animationTransition.type = CATransitionType.fade
    
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 44))
        label.text = <<NEW TITLE TEXT>>
        navigationItem.titleView = label
    
        navigationItem.titleView!.layer.add(animationTransition, forKey: "fadeText")
    }
    
  5. Я также пробовалвключая CAMediaTimingFunction ...

        animationTransition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    
  6. Я также пытался позвонить setNeedsLayout и setNeedsDisplay ...

        navigationItem.titleView?.setNeedsLayout()
        navigationController?.navigationBar.setNeedsDisplay()
    

Для ясности:

  • текст заголовка изменяется, но без анимации;
  • код написан методом viewDidAppear(_ animated:), потому что я хочу, чтобы пользователь виделпереход;
  • длительность (2 секунды) для тестирования - я могу уменьшить это, если / когда анимация работает;
  • Используя инспекторов в раскадровке, я прочиталвсе настройки UITableView / Controller и UINavigationController, чтобы узнать, не пропустил ли я что-то.

Есть предложения?

1 Ответ

1 голос
/ 28 мая 2019

Итак, я решил.

Мне нужно было найти определенный слой в подпредставлениях UINavigationBar, который содержал текст заголовка, а затем анимировать этот слой. Результаты именно то, что я хотел.

Вот мой ответ (Swift 5 iOS 12) ...

override func viewDidAppear(_ animated: Bool) {

    super.viewDidAppear(animated)

    if (newTitle ?? "").isEmpty == false { // only proceed with a valid value for newTitle.

        // CATransition code
        let titleAnimation = CATransition()
        titleAnimation.duration = 0.5
        titleAnimation.type = CATransitionType.push
        titleAnimation.subtype = CATransitionSubtype.fromRight
        titleAnimation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.easeInEaseOut)

        // this is a detail view controller, so we must grab the reference
        // to the parent view controller's navigation controller
        // then cycle through until we find the title labels.
        if let subviews = parent?.navigationController?.navigationBar.subviews {

            for navigationItem in subviews {

                for itemSubView in navigationItem.subviews {

                    if let largeLabel = itemSubView as? UILabel {

                        largeLabel.layer.add(titleAnimation, forKey: "changeTitle")
                    }
                }
            }
        }
        // finally set the title
        navigationItem.title = newTitle
   }

Примечание: нет необходимости import QuartzCore.

GIF of iOS Simulator illustrating CATransition push fromRight

... и вот процесс, который я прошел, чтобы определить, что я должен был изменить ...

Это SO Q & A Как установить многострочный большой заголовок на панели навигации? (Новая функция iOS 11) помог мне определить процесс, подробно описанный ниже, поэтому, в частности, спасибо оригинальному сообщению и ответу @Krunal.

Используя тот же код для циклического просмотра подпредставлений UINavigationBar (как выше), я использовал распечатку для терминала, чтобы идентифицировать различные UINavigationItem s и их подпредставления.

        counter = 0

        if let subviews = parent?.navigationController?.navigationBar.subviews {

            for navigationItem in subviews {

                print("____\(navigationItem)")

                for itemSubView in navigationItem.subviews {

                    counter += 1

                    print("_______\(itemSubView)")
                }
            }
        }
        print("COUNTER: \(counter)")

этот код дал следующие отпечатки в терминале (для iPhone 8 Plus с iOS 12.2 в симуляторе) ...

 ____<_UIBarBackground: 0x7f922740c000; frame = (0 -20; 414 116); userInteractionEnabled = NO; layer = <CALayer: 0x6000026ce1c0>>
 _______<UIImageView: 0x7f922740c9c0; frame = (0 116; 414 0.333333); userInteractionEnabled = NO; layer = <CALayer: 0x6000026ce7c0>>
 _______<UIVisualEffectView: 0x7f922740cbf0; frame = (0 0; 414 116); layer = <CALayer: 0x6000026ce880>>
 ____<_UINavigationBarLargeTitleView: 0x7f922740f390; frame = (0 44; 414 52); clipsToBounds = YES; layer = <CALayer: 0x6000026cd840>>
 _______<UILabel: 0x7f9227499fe0; frame = (20.1667 3.66667; 206.333 40.6667); text = 'Event Details'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000005bf250>>
 ____<_UINavigationBarContentView: 0x7f922740d660; frame = (0 0; 414 44); clipsToBounds = YES; layer = <CALayer: 0x6000026cea00>>
 _______<_UIButtonBarStackView: 0x7f92274984a0; frame = (302 0; 100 44); layer = <CALayer: 0x60000261cc60>>
 _______<_UIButtonBarButton: 0x7f922749a5c0; frame = (0 0; 82.3333 44); layer = <CALayer: 0x60000261ee60>>
 _______<UILabel: 0x7f922749a2d0; frame = (155 11.6667; 104.333 20.3333); text = 'Event Details'; alpha = 0; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6000005bfc50>>
 ____<_UINavigationBarModernPromptView: 0x7f9227602db0; frame = (0 0; 0 50); alpha = 0; hidden = YES; layer = <CALayer: 0x6000026e4600>>
 COUNTER: 2

Я фактически применил анимацию дважды - к UILabel layer в _UINavigationBarLargeTitleView и UILabel layer в _UINavigationBarContentView. Это, похоже, не имеет значения, потому что, когда впервые появляется большой заголовок, метка в представлении содержимого (что, как я полагаю, относится к заголовку «старого стиля» на панели навигации, когда большой заголовок прокручивается за пределами экрана) скрыта viewDidAppear.

Кстати, если вы укажете следующие две строки, у вас также будут большие многострочные заголовки:

 largeLabel.numberOfLines = 0
 largeLabel.lineBreakMode = .byWordWrapping 

НО, я еще не выяснил, как анимировать увеличение размера большого титровального кадра, поэтому изменение на две или более строки происходит немедленно, и ИМХО разрушает анимацию изменения заголовка.

Еще не протестировано на устройстве, но, похоже, работает нормально для симов iPhone и iPad.

Если вы найдете какие-либо ошибки, дайте мне знать, и я обновлю свой ответ.

...