UIView анимировать только в одном контроллере представления - PullRequest
1 голос
/ 01 июля 2019

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

Способ, которым это работает, состоит в том, что у меня есть несколько подпредставлений, которые создают«фон» для потока.Над этими представлениями у меня есть контейнерное представление, в которое встроен контроллер навигации.Этот навигационный контроллер проводит пользователя через процесс регистрации через несколько контроллеров представления.Над этим контейнерным представлением находится «прогрессивный вид», у которого его передний край выровнен с передним краем суперпредставления и который увеличивается по ширине по мере того, как пользователь перемещается по входящим процессам, пока, в конце концов, ширина бара не станет равной ширине экранаи пользователь создал свой профиль.Вот пример того, как это выглядит: Перейдите к 1:53, чтобы увидеть основную проблему

Вот как выглядит содержащий контроллер представления.Обратите внимание на наложение фона, затем представление контейнера, затем представление индикатора выполнения: enter image description here

Этот контроллер представления имеет функцию с именем updateProgressBar, которая принимает процент от ширины экрана доanimate to и затем выполняет анимацию.

func updateProgressBar(to percentAsDecimal: CGFloat!) {
    UIView.animate(withDuration: 0.25) {
        self.progressBarWidth.constant = self.view.frame.width * percentAsDecimal
        self.view.layoutIfNeeded()
    }
}

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

То, что я пробовал: Я создал пользовательские классы, которые являются подклассами UIView, которые используют функцию UIView.performWithoutAnimation, чтобы избежать анимацииsubviews.

import UIKit

class NonAnimatingView: UIView {
    override func layoutSubviews() {
        UIView.performWithoutAnimation {
            super.layoutSubviews()
        }
    }
}

Я сделал что-то подобное с кнопками.

import UIKit

class NonAnimatingButton: UIButton {
    override func layoutSubviews() {
        UIView.performWithoutAnimation {
            super.layoutSubviews()
        }
    }
}

Когда я пытаюсь сделать это с помощью UISearchBar, некоторые анимации разрешаются, но невсе.

import UIKit

class NonAnimatingSearchBar: UISearchBar {
    override func layoutSubviews() {
        UIView.performWithoutAnimation {
            super.layoutSubviews()
        }
    }

    override func addSubview(_ view: UIView) {
        UIView.performWithoutAnimation {
            super.addSubview(view)
        }
    }

    override func insertSubview(_ view: UIView, at index: Int) {
        UIView.performWithoutAnimation {
            super.insertSubview(view, at: index)
        }
    }

    override func insertSubview(_ view: UIView, aboveSubview siblingSubview: UIView) {
        UIView.performWithoutAnimation {
            super.insertSubview(view, aboveSubview: siblingSubview)
        }
    }

    override func insertSubview(_ view: UIView, belowSubview siblingSubview: UIView) {
        UIView.performWithoutAnimation {
            super.insertSubview(view, belowSubview: siblingSubview)
        }
    }

    override func sendSubviewToBack(_ view: UIView) {
        UIView.performWithoutAnimation {
            super.sendSubviewToBack(view)
        }
    }

    override func bringSubviewToFront(_ view: UIView) {
        UIView.performWithoutAnimation {
            super.bringSubviewToFront(view)
        }
    }

    override func exchangeSubview(at index1: Int, withSubviewAt index2: Int) {
        UIView.performWithoutAnimation {
            super.exchangeSubview(at: index1, withSubviewAt: index2)
        }
    }
}

Я также удостоверился, что любые изменения макета, вызываемые до нажатия контроллеров представления контроллера навигации, НЕ анимируются:

override func viewDidLoad() {
    UIView.performWithoutAnimation {
        super.viewDidLoad()
        femaleButton.backgroundColor = UIColor.lightGray.withAlphaComponent(0.25)
        maleButton.backgroundColor = UIColor.lightGray.withAlphaComponent(0.25)
        otherGenderButton.backgroundColor = UIColor.lightGray.withAlphaComponent(0.25)
        femaleButton.layer.cornerRadius = 5
        maleButton.layer.cornerRadius = 5
        otherGenderButton.layer.cornerRadius = 5
        nextButton.layer.cornerRadius = nextButton.frame.height/2
    }
}

Что мне интересно: Есть ли что-то, что я могу вызвать вместо UIView.animate, чтобы я мог анимировать вещи в указанном контроллере представления, не затрагивая все контроллеры представления, видимые в настоящее время?Если нет, то как лучше всего решить эту проблему?

1 Ответ

0 голосов
/ 02 июля 2019

Итак, в итоге я принял совет @ rs7 и вместо него использовал CAShapeLayer. Вместо того чтобы использовать интерфейсный конструктор, я создал CAShapeLayer и добавил его в viewDidLayoutSubviews()

var progressBar: CAShapeLayer!

override func viewDidLayoutSubviews() {

    progressBar = CAShapeLayer()
    progressBar.bounds = CGRect(x: 0, y: 0, width: 0, height: view.safeAreaInsets.top)
    progressBar.position = CGPoint(x: 0, y: 0)
    progressBar.anchorPoint = CGPoint(x: 0, y: 0)
    progressBar.backgroundColor = UIColor.secondaryColor.cgColor
    view.layer.addSublayer(progressBar)
}

Затем я обновил updateProgressBar, чтобы изменить CALayer вместо NSLayoutConstraint константы.

func updateProgressBar(to percentAsDecimal: CGFloat!) {
    let newWidth = view.bounds.width * percentAsDecimal
    CATransaction.begin()
    CATransaction.setCompletionBlock({
        self.progressBar.bounds.size.width = newWidth
    })
    CATransaction.commit()
    let anim = CABasicAnimation(keyPath: "bounds")
    anim.isRemovedOnCompletion = false
    anim.fillMode = .forwards
    anim.duration = 0.25
    anim.fromValue = NSValue(cgRect: CGRect(x: 0, y: 0, width: progressBar.bounds.width, height: view.safeAreaInsets.top))
    anim.toValue = NSValue(cgRect: CGRect(x: 0, y: 0, width: newWidth, height: view.safeAreaInsets.top))
    progressBar.add(anim, forKey: "anim")
}

Теперь больше нет необходимости в моем кастоме NonAnimatingView, NonAnimatingButton или NonAnimatingSearchBar. :)

...