Модальный навигационный контроллер с размытым фоном, плавный во время анимации нажатия? - PullRequest
0 голосов
/ 12 октября 2018

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

Раскадровка выглядит следующим образом:

enter image description here

Теперь нужно применить эффект размытия к всему контроллеру навигации , так что изображение в контроллере начального вида можно увидеть снизу.

Я несколько преуспел в применении одного и того же эффекта размытия как к контроллеру табличного представления, так и к контроллеру подробного просмотра, например:

Контроллер табличного представления

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.tableFooterView = UIView(frame: .zero)

        tableView.backgroundColor = UIColor.clear
        let blurEffect = UIBlurEffect(style: .dark)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        tableView.backgroundView = blurEffectView
        tableView.separatorEffect = UIVibrancyEffect(blurEffect: blurEffect)
    }
}

Контроллер подробного просмотра

class DetailViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .clear
        let blurEffect = UIBlurEffect(style: .dark)
        let blurView = UIVisualEffectView(effect: blurEffect)
        blurView.translatesAutoresizingMaskIntoConstraints = false
        view.insertSubview(blurView, at: 0)
        NSLayoutConstraint.activate([
            blurView.heightAnchor.constraint(equalTo: view.heightAnchor),
            blurView.widthAnchor.constraint(equalTo: view.widthAnchor),
        ])
    }
}

(я также устанавливаю модальное представлениестиль навигации к .overFullScreen) .

Однако, в конце перехода к контроллеру подробного вида, раздражающий артефакт можетможно увидеть на размытом фоне:

enter image description here

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

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

Что такоеправильный способ применить размытие фона / эффект вибрации к содержимому контроллера навигации, без проблем?

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Как я выяснил в этом вопросе, анимированные переходы push / pop, представленные начиная с iOS 7 (где контроллер представления, расположенный ниже в стеке навигации, "выдвигается на половину скорости", так чтоон перекрывает тот, который был нажат / вытолкнут) делает невозможным переход между контроллерами прозрачного представления без артефактов.

Поэтому я решил принять протокол UINavigationControllerDelegate, точнее метод: navigationController(_:animationControllerFor:from:to:), по существу реплицирует анимированные переходы UINavigationController с нуля.

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

До сих пор я только реализовал операцию push (в конце концов, мне придется делать popоперации, а также интерактивное всплывающее окно, основанное на жестах, поп-форма), Я создал пользовательский UINavigationController подкласс и положить его на GitHub .

(В настоящее время он поддерживает анимированные push и pop, но не интерактивность. Кроме того, я пока не понял, как воспроизвести анимацию «слайда» заголовка панели навигации - она ​​просто пересекается.)

Это сводится к следующим шагам:

  1. Изначально преобразуйте вид .to вправо, вне экрана.Во время анимации постепенно преобразуйте его обратно в идентичность (центр экрана).
  2. Установите белый UIView как mask для .from вида, первоначально с границами, равными .from вид (без маскировки).Во время анимации постепенно уменьшайте ширину свойства frame маски до половины его первоначального значения.
  3. Во время анимации постепенно переводите представление from наполовину за кадром влево.

В коде:

class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {

    // Super slow for debugging:
    let duration: TimeInterval = 1

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromView = transitionContext.view(forKey: .from) else {
            return
        }
        guard let toView = transitionContext.view(forKey: .to) else {
            return
        }
        guard let toViewController = transitionContext.viewController(forKey: .to) else {
            return
        }

        //
        // (Code below assumes navigation PUSH operation. For POP, 
        //  use similar code but with view roles and direction 
        //  reversed)
        //

        // Add target view to container:
        transitionContext.containerView.addSubview(toView)

        // Set tagret view frame, centered on screen
        let toViewFinalFrame = transitionContext.finalFrame(for: toViewController)
        toView.frame = toViewFinalFrame
        let containerBounds = transitionContext.containerView.bounds
        toView.center = CGPoint(x: containerBounds.midX, y: containerBounds.midY)

        // But translate it to fully the RIGHT, for now:
        toView.transform = CGAffineTransform(translationX: containerBounds.width, y: 0)

        // We will slide the source view out, to the LEFT, by half as much:
        let fromTransform = CGAffineTransform(translationX: -0.5*containerBounds.width, y: 0)

        // Apply a white UIView as mask to the source view:
        let maskView = UIView(frame: CGRect(origin: .zero, size: fromView.frame.size))
        maskView.backgroundColor = .white
        fromView.mask = maskView

        // The mask will shrink to half the width during the animation:
        let maskViewNewFrame = CGRect(origin: .zero, size: CGSize(width: 0.5*fromView.frame.width, height: fromView.frame.height))

        // Animate:
        UIView.animate(withDuration: duration, delay: 0, options: [.curveEaseOut], animations: {

            fromView.transform = fromTransform // off-screen to the left (half)

            toView.transform = .identity // Back on screen, fully centered

            maskView.frame = maskViewNewFrame // Mask to half width

        }, completion: {(completed) in

            // Remove mask, or funny things will happen to a 
            // table view or scroll view if the user 
            // "rubber-bands":
            fromView.mask = nil

            transitionContext.completeTransition(completed)
        })
    }

Результат:

enter image description here

(я добавилтекстовый вид на контроллер детального вида для наглядности)

0 голосов
/ 12 октября 2018

Попробуйте следующие шаги.Я не пробовал, но он должен работать.

  1. Добавить фоновое изображение в окно в didFinishLaunchingWithOptions и скрыть его по умолчанию.
  2. Добавить такое же изображение в представляемый контроллер модального вида.
  3. Обязательно очистите фон вашего контроллера представления.
  4. Поэтому, когда вы представите, он покажет то изображение, которое находится в контроллере модального представления.
  5. После завершения Показать изображение окна искрыть изображение контроллера вида.
  6. Когда вы нажимаете кнопку «назад», чтобы закрыть вид, сначала раскройте изображение контроллера вида и скройте изображение окна.Так что ваша анимация будет выглядеть нормально.

Дайте мне знать, если вам нужна помощь.

...