Push анимация без теней и затемнений
У меня простая iOS NavigationController
на основе приложения. Два UICollectionViews
, один за другим. Если щелкнуть элемент в "первой коллекции", откроется "вторая коллекция". Достаточно просто.
Важная заметка:
"И то и другое UICollectionViews
иметь прозрачный фон. Общий цвет фона для navigationController
используется. (Унаследованный класс от UINavigationController
) "
Проблема: если все правильно поняли, нажмите метод NavigationController
работает по алгоритму:
- Pushing view создан.
- Прозрачное серое наложение создается поверх толкающего вида.
- NavigationController перемещает представление со стандартной анимацией. (Серое наложение все еще там)
- Серое наложение исчезает.
(Если у толкающего вида прозрачный фон, видна серая вертикальная линия)
Следующий шаг: я попытался решить эту проблему, переопределив метод push. Вот что у меня есть:
- (void)pushViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
CATransition *transition = [CATransition animation];
transition.duration = 0.45;
transition.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.fillMode = kCAFillModeForwards;
transition.delegate = self;
[self.view.layer addAnimation:transition forKey:nil];
[super pushViewController:viewController animated:animated];
}
Этот способ создает свою собственную анимацию push, но были использованы другие стандартные анимации, которые я не могу удалить. (Затемнение при представлении и скрытии видов)
Вопрос: "Как я могу нажать ViewController, без затухания, затемнения и других фильтров анимации?"
Решения с названиями тем (на stackru.com)
- IOS 7
UINavigationController
Нажмите анимацию тени - iOS 7 показывает черный фон в пользовательской анимации для навигации
Не работает
3 ответа
Не переопределяйте метод push. iOS7 позволяет предоставлять контроллеры анимации для пользовательских переходов. Смотрите здесь для более подробной информации.
Я долго боролся с этим и в конце концов придумал довольно хакерский способ сделать это, который, кажется, отлично работает.
class UINavigationControllerKillDim: UINavigationController {
private weak var displayLink: CADisplayLink?
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
displayLink?.invalidate()
let displayLink = CADisplayLink(target: self, selector: #selector(linkTriggered))
displayLink.add(to: .main, forMode: .default)
self.displayLink = displayLink
super.pushViewController(viewController, animated: animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
displayLink?.invalidate()
}
@objc func linkTriggered(displaylink: CADisplayLink) {
let parallaxViews = self.view.allParallaxSubviews()
parallaxViews.forEach({ parallaxView in
parallaxView.backgroundColor = UIColor.clear
})
}
deinit{
displayLink?.invalidate()
}
}
private extension UIView {
func allParallaxSubviews() -> [UIView]{
var all = [UIView]()
func getSubview(view: UIView) {
if String(describing: type(of: view)) == "_UIParallaxDimmingView" {
all.append(view)
}
guard !view.subviews.isEmpty else { return }
view.subviews.forEach{ getSubview(view: $0) }
}
getSubview(view: self)
return all
}
}
В основном он находит каждый UIParallaxDimmingView (их 2) и устанавливает цвет фона для очистки в каждом кадре.
Я думаю, что использование setBackgroundColor в _UIParallaxDimmingView может быть лучшим путем, но я не мог понять, как использовать метод внутри частного класса.
Была такая же проблема с размытыми прозрачными контроллерами представления. Затемняющий вид откладывается во время перехода.
Я должен признать, что мне очень нравятся нативные переходы iOS (особенно с большими заголовками), и я думаю, что для их воспроизведения с тем же уровнем качества требуется довольно много времени. Я наткнулся на множество руководств, объясняющих, как создавать пользовательские переходы, но результат выглядел довольно странно (в Snapchat есть собственные интерактивные переходы UIScrollView со страницы на страницу, и лично я нахожу пользовательский опыт странным, потому что 90% других моих приложений имеют родные переходы Apple)
В любом случае, если у кого-то есть такая же проблема с нажатием полупрозрачных контроллеров представления, вот моя реализация
Обратите внимание, что это все еще довольно глупо и может не работать в будущих версиях iOS. Поправьте меня, если я пропущу лучший способ «отменить» собственные переходы iOS VC.
override func pushViewController(_ viewController: UIViewController, animated: Bool)
{
let visibleVc = self.visibleViewController
super.pushViewController(viewController, animated: animated)
if(animated)
{
UIView.animate(withDuration:transitionCoordinator?.transitionDuration ?? 0.2, animations: {
visibleVc?.view.alpha = 0
})
}
// at least in iOS 13, pushing a viewController creates, the time of the transition,
// a dimming view that disappear only after the old view controller is removed.
// this causes the blur to jump a tiny bit in brightness at the end of the push animation
// to remove that "jump", we find the dimming view after a while (it's not present at the beginning), and animate it to alpha 0, from half animation time
// FIXME: this is only a silly trick : it would be appropriate to create our own VC transition later
// Works at least with iOS 13, to be tested with iOS < 13 and iOS 14
let halfDuration = (transitionCoordinator?.transitionDuration ?? 0.2) / 2
DispatchQueue.main.asyncAfter(deadline:.now() + halfDuration ) {
if let uiNavigationTransitionView = self.view.subviews.first(where: {
String(describing: type(of: $0)) == "UINavigationTransitionView"
}),
let wrapperView = uiNavigationTransitionView.subviews.first(where: {
String(describing: type(of: $0)) == "UIViewControllerWrapperView"
}),
let grayOverlay = wrapperView.subviews.first(where: {
String(describing: type(of: $0)) == "_UIParallaxDimmingView"
})
{
UIView.animate(withDuration:halfDuration, animations: {
grayOverlay.alpha = 0
})
}
}
}