Odpowiedzi:
W systemie iOS 4 i nowszych można to zrobić po prostu przy użyciu metody przejścia UIView bez konieczności importowania QuartzCore. Możesz po prostu powiedzieć:
[UIView transitionWithView:button
duration:0.4
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
button.hidden = YES;
}
completion:NULL];
UIView.transition(with: button, duration: 0.4,
options: .transitionCrossDissolve,
animations: {
button.hidden = false
})
Rozwiązanie Michail zadziała, ale tak naprawdę nie jest to najlepsze podejście.
Problem z zanikaniem alfa polega na tym, że czasami różne nakładające się warstwy widoku wyglądają dziwnie, gdy zanikają. Istnieje kilka innych możliwości korzystania z Core Animation. Najpierw umieść strukturę QuartzCore w swojej aplikacji i dodaj #import <QuartzCore/QuartzCore.h>
do nagłówka. Teraz możesz wykonać jedną z następujących czynności:
1) ustaw, button.layer.shouldRasterize = YES;
a następnie użyj kodu animacji alfa, który podał Michail w swojej odpowiedzi. Zapobiegnie to dziwnemu mieszaniu się warstw, ale ma niewielki spadek wydajności i może sprawić, że przycisk będzie wyglądał na rozmazany, jeśli nie jest dokładnie wyrównany na granicy pikseli.
Alternatywnie:
2) Zamiast tego użyj następującego kodu, aby animować zanikanie:
CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 0.4;
[button.layer addAnimation:animation forKey:nil];
button.hidden = YES;
Zaletą tego podejścia jest to, że możesz przenikać dowolną właściwość przycisku, nawet jeśli nie można jej animować (np. Tekst lub obraz przycisku), po prostu skonfiguruj przejście, a następnie ustaw swoje właściwości.
transitionWithView
parametru, aby zapewnić pomyślne włączanie i wyłączanie.
Animowane właściwości UIView to:
- frame
- bounds
- center
- transform
- alpha
- backgroundColor
- contentStretch
Opisz w: Animacje
isHidden
nie jest jednym z nich, więc jak to widzę najlepiej jest:
Swift 4:
func setView(view: UIView, hidden: Bool) {
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
view.isHidden = hidden
})
}
Cel C:
- (void)setView:(UIView*)view hidden:(BOOL)hidden {
[UIView transitionWithView:view duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^(void){
[view setHidden:hidden];
} completion:nil];
}
Aby zniknąć:
Cel C
[UIView animateWithDuration:0.3 animations:^{
button.alpha = 0;
} completion: ^(BOOL finished) {//creates a variable (BOOL) called "finished" that is set to *YES* when animation IS completed.
button.hidden = finished;//if animation is finished ("finished" == *YES*), then hidden = "finished" ... (aka hidden = *YES*)
}];
Szybki 2
UIView.animateWithDuration(0.3, animations: {
button.alpha = 0
}) { (finished) in
button.hidden = finished
}
Swift 3, 4, 5
UIView.animate(withDuration: 0.3, animations: {
button.alpha = 0
}) { (finished) in
button.isHidden = finished
}
Aby wprowadzić:
Cel C
button.alpha = 0;
button.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
button.alpha = 1;
}];
Szybki 2
button.alpha = 0
button.hidden = false
UIView.animateWithDuration(0.3) {
button.alpha = 1
}
Swift 3, 4, 5
button.alpha = 0
button.isHidden = false
UIView.animate(withDuration: 0.3) {
button.alpha = 1
}
Używam tego małego rozszerzenia Swift 3 :
extension UIView {
func fadeIn(duration: TimeInterval = 0.5,
delay: TimeInterval = 0.0,
completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
UIView.animate(withDuration: duration,
delay: delay,
options: UIViewAnimationOptions.curveEaseIn,
animations: {
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: TimeInterval = 0.5,
delay: TimeInterval = 0.0,
completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
UIView.animate(withDuration: duration,
delay: delay,
options: UIViewAnimationOptions.curveEaseIn,
animations: {
self.alpha = 0.0
}, completion: completion)
}
}
szybki 4.2
z rozszerzeniem:
extension UIView {
func hideWithAnimation(hidden: Bool) {
UIView.transition(with: self, duration: 0.5, options: .transitionCrossDissolve, animations: {
self.isHidden = hidden
})
}
}
prosta metoda:
func setView(view: UIView, hidden: Bool) {
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
view.isHidden = hidden
})
}
Użyj tego rozwiązania, aby uzyskać płynne efekty zanikania i zanikania
extension UIView {
func fadeIn(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
self.alpha = 0.0
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.isHidden = false
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
self.alpha = 1.0
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseOut, animations: {
self.isHidden = true
self.alpha = 0.0
}, completion: completion)
}
}
użycie jest jak podobne
uielement.fadeIn()
uielement.fadeOut()
Dzięki
fadeOut
działa na iOS 13 tylko wtedy, gdy usunę ustawione linie self.isHidden
.
I stworzył kategorię UIView
do tego celu i wdrożony specjalny nieco inną koncepcję: visibility
. Główną różnicą w moim rozwiązaniu jest to, że możesz zadzwonić [view setVisible:NO animated:YES]
i zaraz po tym synchronicznie sprawdzić [view visible]
i uzyskać poprawny wynik. Jest to dość proste, ale niezwykle przydatne.
Poza tym dozwolone jest unikanie stosowania „negatywnej logiki boolowskiej” (zobacz Code Complete, strona 269, Użyj dodatnich nazw zmiennych boolowskich, aby uzyskać więcej informacji).
UIView+Visibility.swift
import UIKit
private let UIViewVisibilityShowAnimationKey = "UIViewVisibilityShowAnimationKey"
private let UIViewVisibilityHideAnimationKey = "UIViewVisibilityHideAnimationKey"
private class UIViewAnimationDelegate: NSObject {
weak var view: UIView?
dynamic override func animationDidStop(animation: CAAnimation, finished: Bool) {
guard let view = self.view where finished else {
return
}
view.hidden = !view.visible
view.removeVisibilityAnimations()
}
}
extension UIView {
private func removeVisibilityAnimations() {
self.layer.removeAnimationForKey(UIViewVisibilityShowAnimationKey)
self.layer.removeAnimationForKey(UIViewVisibilityHideAnimationKey)
}
var visible: Bool {
get {
return !self.hidden && self.layer.animationForKey(UIViewVisibilityHideAnimationKey) == nil
}
set {
let visible = newValue
guard self.visible != visible else {
return
}
let animated = UIView.areAnimationsEnabled()
self.removeVisibilityAnimations()
guard animated else {
self.hidden = !visible
return
}
self.hidden = false
let delegate = UIViewAnimationDelegate()
delegate.view = self
let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = visible ? 0.0 : 1.0
animation.toValue = visible ? 1.0 : 0.0
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
animation.delegate = delegate
self.layer.addAnimation(animation, forKey: visible ? UIViewVisibilityShowAnimationKey : UIViewVisibilityHideAnimationKey)
}
}
func setVisible(visible: Bool, animated: Bool) {
let wereAnimationsEnabled = UIView.areAnimationsEnabled()
if wereAnimationsEnabled != animated {
UIView.setAnimationsEnabled(animated)
defer { UIView.setAnimationsEnabled(!animated) }
}
self.visible = visible
}
}
UIView+Visibility.h
#import <UIKit/UIKit.h>
@interface UIView (Visibility)
- (BOOL)visible;
- (void)setVisible:(BOOL)visible;
- (void)setVisible:(BOOL)visible animated:(BOOL)animated;
@end
UIView+Visibility.m
#import "UIView+Visibility.h"
NSString *const UIViewVisibilityAnimationKeyShow = @"UIViewVisibilityAnimationKeyShow";
NSString *const UIViewVisibilityAnimationKeyHide = @"UIViewVisibilityAnimationKeyHide";
@implementation UIView (Visibility)
- (BOOL)visible
{
if (self.hidden || [self.layer animationForKey:UIViewVisibilityAnimationKeyHide]) {
return NO;
}
return YES;
}
- (void)setVisible:(BOOL)visible
{
[self setVisible:visible animated:NO];
}
- (void)setVisible:(BOOL)visible animated:(BOOL)animated
{
if (self.visible == visible) {
return;
}
[self.layer removeAnimationForKey:UIViewVisibilityAnimationKeyShow];
[self.layer removeAnimationForKey:UIViewVisibilityAnimationKeyHide];
if (!animated) {
self.alpha = 1.f;
self.hidden = !visible;
return;
}
self.hidden = NO;
CGFloat fromAlpha = visible ? 0.f : 1.f;
CGFloat toAlpha = visible ? 1.f : 0.f;
NSString *animationKey = visible ? UIViewVisibilityAnimationKeyShow : UIViewVisibilityAnimationKeyHide;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.duration = 0.25;
animation.fromValue = @(fromAlpha);
animation.toValue = @(toAlpha);
animation.delegate = self;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[self.layer addAnimation:animation forKey:animationKey];
}
#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
{
if ([[self.layer animationForKey:UIViewVisibilityAnimationKeyHide] isEqual:animation]) {
self.hidden = YES;
}
}
@end
kod @Umair Afzal działa dobrze w Swift 5 po pewnych zmianach
extension UIView {
func fadeIn(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
self.alpha = 0.0
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.isHidden = false
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
self.alpha = 1.0
UIView.animate(withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: {
self.alpha = 0.0
}) { (completed) in
self.isHidden = true
completion(true)
}
}
}
do użycia
yourView.fadeOut()
yourView.fadeIn()
Szybki 4
extension UIView {
func fadeIn(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in }) {
self.alpha = 0.0
UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.isHidden = false
self.alpha = 1.0
}, completion: completion)
}
func fadeOut(duration: TimeInterval = 0.5, delay: TimeInterval = 0.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in }) {
self.alpha = 1.0
UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = 0.0
}) { (completed) in
self.isHidden = true
completion(true)
}
}
}
Aby z niego skorzystać, po prostu wywołaj te funkcje, takie jak:
yourView.fadeOut() // this will hide your view with animation
yourView.fadeIn() /// this will show your view with animation
isHidden
jest wartością natychmiastową i nie możesz wpłynąć na animację na niej, zamiast tego możesz użyć Alpha do ukrycia widoku
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
view.alpha = 0
})
I za pokazanie:
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
view.alpha = 1
})
Możesz to BARDZO łatwo zrobić używając biblioteki Animatics :
//To hide button:
AlphaAnimator(0) ~> button
//to show button
AlphaAnimator(1) ~> button
func flipViews(fromView: UIView, toView: UIView) {
toView.frame.origin.y = 0
self.view.isUserInteractionEnabled = false
UIView.transition(from: fromView, to: toView, duration: 0.5, options: .transitionFlipFromLeft, completion: { finished in
fromView.frame.origin.y = -900
self.view.isUserInteractionEnabled = true
})
}
Możesz tego spróbować.
func showView(objView:UIView){
objView.alpha = 0.0
UIView.animate(withDuration: 0.5, animations: {
objView.alpha = 0.0
}, completion: { (completeFadein: Bool) -> Void in
objView.alpha = 1.0
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade
objView.layer.add(transition, forKey: nil)
})
}
func HideView(objView:UIView){
UIView.animate(withDuration: 0.5, animations: {
objView.alpha = 1.0
}, completion: { (completeFadein: Bool) -> Void in
objView.alpha = 0.0
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade
objView.layer.add(transition, forKey: nil)
})
}
I podaj nazwę swojego widoku
showView(objView: self.viewSaveCard)
HideView(objView: self.viewSaveCard)
Jeśli twój widok jest domyślnie ustawiony na ukryty lub zmienisz stan Ukryty, który myślę, że powinieneś w wielu przypadkach, to żadne z podejść na tej stronie nie da ci animacji FadeIn / FadeOut, animuje tylko jeden z tych stanów, powodem jest to, że ustawiasz stan Hidden na false przed wywołaniem metody UIView.animate , która spowoduje nagłą widoczność i jeśli animujesz tylko alfa, przestrzeń obiektu nadal istnieje, ale nie jest widoczna, co spowoduje pewne problemy z interfejsem użytkownika.
Najlepszym podejściem jest więc najpierw sprawdzenie, czy widok jest ukryty, a następnie ustawienie alfa na 0,0, w ten sposób, gdy ustawisz stan Ukryty na fałsz, nie zobaczysz nagłej widoczności.
func hideViewWithFade(_ view: UIView) {
if view.isHidden {
view.alpha = 0.0
}
view.isHidden = false
UIView.animate(withDuration: 0.3, delay: 0.0, options: .transitionCrossDissolve, animations: {
view.alpha = view.alpha == 1.0 ? 0.0 : 1.0
}, completion: { _ in
view.isHidden = !Bool(truncating: view.alpha as NSNumber)
})
}
UIView.transition (z :) funkcja jest ładna i schludna.
Wielu to opublikowało, ale nikt nie zauważył, że błąd pojawi się dopiero po uruchomieniu.
Możesz perfekcyjnie zmienić ukrytą właściwość na true, podczas gdy gdy spróbujesz zmienić ją na false, widok po prostu nagle zniknie bez żadnej animacji.
Dzieje się tak, ponieważ ten interfejs API działa tylko w widoku, co oznacza, że po przejściu widoku do pokazania, w rzeczywistości sam pokazuje natychmiast, tylko jego zawartość jest animowana stopniowo.
Kiedy próbujesz ukryć ten widok, sam się ukryje od razu, sprawia, że animacja jest bez znaczenia.
Aby rozwiązać ten problem, podczas ukrywania widoku celem przejścia powinien być jego widok nadrzędny, a nie widok, który chcesz ukryć.
func transitionView(_ view: UIView?, show: Bool, completion: BoolFunc? = nil) {
guard let view = view, view.isHidden == show, let parent = view.superview else { return }
let target: UIView = show ? view : parent
UIView.transition(with: target, duration: 0.4, options: [.transitionCrossDissolve], animations: {
view.isHidden = !show
}, completion: completion)
}
Moje rozwiązanie dla Swift 3 . Stworzyłem więc funkcję, która ukrywa / odkrywa widok we właściwej kolejności (podczas ukrycia - ustaw alfa na 0, a potem isHidden na true; odkrywanie - najpierw odsłoń widok, a potem ustaw jego alfa na 1):
func hide(_ hide: Bool) {
let animations = hide ? { self.alpha = 0 } :
{ self.isHidden = false }
let completion: (Bool) -> Void = hide ? { _ in self.isHidden = true } :
{ _ in UIView.animate(withDuration: duration, animations: { self.alpha = 1 }) }
UIView.animate(withDuration: duration, animations: animations, completion: completion)
}
completion
bloku jest inna animacja, kiedy hide
jest fałszywa?
Swift 4 Transition
UIView.transition(with: view, duration: 3, options: .transitionCurlDown,
animations: {
// Animations
view.isHidden = hidden
},
completion: { finished in
// Compeleted
})
Jeśli zastosujesz podejście do starszych wersji Swift, pojawi się błąd:
Cannot convert value of type '(_) -> ()' to expected argument type '(() -> Void)?'
Przydatne odniesienia .
isHidden
wartość staje się natychmiast (tj natychmiast ukrywanie / pokazywanie widoku).
Ten kod daje animację, taką jak wypychanie viewController w kontrolerze uinavigation ...
CATransition *animation = [CATransition animation];
animation.type = kCATransitionPush;
animation.subtype = kCATransitionFromRight;
animation.duration = 0.3;
[_viewAccountName.layer addAnimation:animation forKey:nil];
_viewAccountName.hidden = true;
Użyłem tego do animacji pop ...
CATransition *animation = [CATransition animation];
animation.type = kCATransitionPush;
animation.subtype = kCATransitionFromLeft;
animation.duration = 0.3;
[_viewAccountName.layer addAnimation:animation forKey:nil];
_viewAccountName.hidden = false;
Wypróbowałem niektóre z opuszczonych odpowiedzi, niektóre działają tylko w jednej sytuacji, a niektóre z nich wymagają dodania dwóch funkcji.
opcja 1
Nie ma z tym nic wspólnego view.isHidden
.
extension UIView {
func animate(fadeIn: Bool, withDuration: TimeInterval = 1.0) {
UIView.animate(withDuration: withDuration, delay: 0.0, options: .curveEaseInOut, animations: {
self.alpha = fadeIn ? 1.0 : 0.0
})
}
}
Następnie przejdź isFadeIn
( true
lub false
)
view.animate(fadeIn: isFadeIn)
Opcja 2
Nie przekazuj żadnego parametru. Zanika lub zanika zgodnie z isUserInteractionEnabled
. To również bardzo dobrze pasuje do sytuacji, w której animowane są tam iz powrotem.
func animateFadeInOut(withDuration: TimeInterval = 1.0) {
self.isUserInteractionEnabled = !self.isUserInteractionEnabled
UIView.animate(withDuration: withDuration, delay: 0.0, options: .curveEaseInOut, animations: {
self.alpha = self.isUserInteractionEnabled ? 1.0 : 0.0
})
}
Wtedy dzwonisz
yourView.animateFadeInOut()
Dlaczego
self.isUserInteractionEnabled
?Starał się zastąpić
self.isUserInteractionEnabled
przezself.isHidden
, bez powodzenia w ogóle.
Otóż to. Kosztuje mnie kiedyś, mam nadzieję, że to komuś pomoże.