UIView Скрыть / Показать с анимацией

154

Моя простая цель - убрать анимацию, скрывая и показывая функции.

Button.hidden = YES;

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

JTApps
источник

Ответы:

259

В iOS 4 и более поздних версиях есть способ сделать это, просто используя метод перехода UIView без необходимости импортировать QuartzCore. Вы можете просто сказать:

Цель С

[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
              })

Предыдущее решение

Решение Михаила будет работать, но на самом деле это не лучший подход.

Проблема с альфа-замиранием заключается в том, что иногда разные перекрывающиеся слои вида выглядят странно по мере их исчезновения. Есть несколько других альтернатив, использующих Core Animation. Сначала включите в приложение фреймворк QuartzCore и добавьте его #import <QuartzCore/QuartzCore.h>в заголовок. Теперь вы можете сделать одно из следующего:

1) установить button.layer.shouldRasterize = YES;и затем использовать код альфа-анимации, который Михаил предоставил в своем ответе. Это предотвратит странное смешивание слоев, но приведет к небольшому снижению производительности и может привести к тому, что кнопка будет выглядеть размытой, если она не выровнена точно по границе пикселей.

В качестве альтернативы:

2) Используйте следующий код для анимации затухания:

CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.duration = 0.4;
[button.layer addAnimation:animation forKey:nil];

button.hidden = YES;

Хорошая вещь в этом подходе заключается в том, что вы можете плавно изменять любое свойство кнопки, даже если они не анимируемы (например, текст или изображение кнопки), просто установите переход, а затем сразу же установите свои свойства.

Ник Локвуд
источник
5
@robmathers, я просто проверяю ваш код, выше двух кодов просто работают, когда button.hidden = NO, для исчезновения в ситуации; не имеют эффекта анимации для затухания, когда button.hidden = YES;
Джейсон
Кажется, сломан в iOS 12.0
user3532505
5
Вы должны использовать супервидение того, что вы анимируете, как transitionWithViewпараметр, чтобы обеспечить успешное появление и исчезновение.
Аллен
159

Анимированные свойства UIView:

- frame
- bounds
- center
- transform
- alpha
- backgroundColor
- contentStretch

Опишите в: Анимации

isHidden не один из них, так что, на мой взгляд, лучший способ это:

Свифт 4:

func setView(view: UIView, hidden: Bool) {
    UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
        view.isHidden = hidden
    })
}

Цель C:

- (void)setView:(UIView*)view hidden:(BOOL)hidden {
    [UIView transitionWithView:view duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^(void){
        [view setHidden:hidden];
    } completion:nil];
}
evya
источник
8
На самом деле это простой и лучший ответ
Иршад Мухаммед
3
Хотя это правильно анимируется, UISearchBar, который я пытаюсь отобразить, появляется в неправильном месте, пока анимация не завершится, а затем мгновенно не перейдет в правильное положение. Любая идея? Я использую Раскадровки с Интерфейсным Разработчиком и Ограничениями.
Грег Хилстон
5
Этот код не работает ... он напрямую меняет состояние без анимации
Михир Мехта
2
@evya Работать только для затухания, когда скрыто = НЕТ , Не работать для затухания, скрыто = ДА
Джейсон
Потрясающие. В 10 раз больше
Вячеслав
125

Чтобы исчезнуть:

Objective-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*)
}];

Swift 2

UIView.animateWithDuration(0.3, animations: {
    button.alpha = 0
}) { (finished) in
    button.hidden = finished
}

Свифт 3, 4, 5

UIView.animate(withDuration: 0.3, animations: {
    button.alpha = 0
}) { (finished) in
    button.isHidden = finished
}

Чтобы исчезнуть:

Objective-C

button.alpha = 0;
button.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
    button.alpha = 1;
}];

Swift 2

button.alpha = 0
button.hidden = false
UIView.animateWithDuration(0.3) {
    button.alpha = 1
}

Свифт 3, 4, 5

button.alpha = 0
button.isHidden = false
UIView.animate(withDuration: 0.3) {
    button.alpha = 1
}
Михаил Гребионкин
источник
Использование
Fade In
По какой-то причине анимация скрытого = ДА работала нормально для меня, но анимация скрытого = НЕТ ничего не делала, поэтому эта комбинация анимации альфа и установки скрытого свойства была полезной.
arlomedia
Я просто пишу демо, но только скрытый = НЕТ, исчезают в работах, странно
Джейсон
9

Я использую это небольшое расширение 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)
  }
}
Марк Маккельви
источник
7

Swift 3

func appearView() {
     self.myView.alpha = 0
     self.myView.isHidden = false

     UIView.animate(withDuration: 0.9, animations: {
         self.myView.alpha = 1
     }, completion: {
         finished in
         self.myView.isHidden = false
     })
}
Scaraux
источник
7

Swift 4.2

с расширением:

extension UIView {
func hideWithAnimation(hidden: Bool) {
        UIView.transition(with: self, duration: 0.5, options: .transitionCrossDissolve, animations: {
            self.isHidden = hidden
        })
    }
}

простой метод:

func setView(view: UIView, hidden: Bool) {
    UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
        view.isHidden = hidden
    })
}
Мохен мохтари
источник
Как я могу добавить задержку для этого?
cvdogan
7

Используйте это решение для плавных эффектов затухания и затухания

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)
    }
}

использование как

uielement.fadeIn()
uielement.fadeOut()

Спасибо

Дхану К
источник
fadeOutработает на iOS 13, только если я удаляю строки, которые установлены self.isHidden.
Майк Таверн
6

Я создал категорию UIViewдля этой цели и реализован специальный немного другое понятие: visibility. Основное отличие моего решения в том, что вы можете позвонить [view setVisible:NO animated:YES]и сразу после этого синхронно проверить[view visible] и получить правильный результат. Это довольно просто, но чрезвычайно полезно.

Кроме того, разрешено избегать использования «отрицательной логической логики» (см. Code Complete, стр. 269, используйте положительные имена логических переменных для получения дополнительной информации).

стриж

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
    }

}

Objective-C

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
Валентин Шергин
источник
@valentin shergin Скоро будет версия Swift?
Хуан Боэро
Конечно! Я добавил версию Swift.
Валентин Шергин
5

Код @Umair Afzal работает хорошо в Swift 5 после некоторых изменений

 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)
    }
  }
}

для использования

yourView.fadeOut()
yourView.fadeIn()
Санджай Мишра
источник
придавая некоторый жесткий эффект во время затухания, добавил здесь
Dhanu K
4

Swift 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)
    }
}
}

И чтобы использовать его, просто вызовите эти функции, такие как:

yourView.fadeOut() // this will hide your view with animation
yourView.fadeIn() /// this will show your view with animation
Умайр Афзал
источник
Вы только что скопировали ответ @ MarkMckelvie
Эшли Миллс
Есть разница, он не скрывал взгляд. И мне нужно было также скрыть вид. Так и сделал и поделился этим.
Umair Afzal
3
Почему бы просто не прокомментировать другой ответ, а не скопировать его и выдать за свой собственный?
Эшли Миллс
2

isHidden является непосредственным значением, и вы не можете повлиять на анимацию, вместо этого вы можете использовать Alpha для скрытия вашего вида

UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
        view.alpha = 0
    })

И для показа:

UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
      view.alpha = 1
})
Мохсен
источник
1

Вы можете сделать это ОЧЕНЬ легко, используя библиотеку Animatics :

//To hide button:
AlphaAnimator(0) ~> button

//to show button
AlphaAnimator(1) ~> button
Никита Архипов
источник
1
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

    })


}
Вимал Сайфудин
источник
1

Вы можете попробовать это.

 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)
    })
}

И передать свое имя просмотра

        showView(objView: self.viewSaveCard)
        HideView(objView: self.viewSaveCard)
Kalpesh
источник
1

Если ваш вид по умолчанию скрыт или вы изменяете скрытое состояние, которое, как я думаю, вам следует во многих случаях, то ни один из подходов на этой странице не обеспечит вам анимацию FadeIn / FadeOut, а только анимацию одного из этих состояний, причина в том, что вы устанавливаете скрытое состояние в false перед вызовом метода UIView.animate, который вызывает внезапную видимость, и если вы только анимируете альфа, то пространство объектов все еще там, но оно не видно, что приведет к некоторым проблемам с пользовательским интерфейсом.

Поэтому лучше всего сначала проверить, является ли вид скрытым, а затем установить альфа в 0.0, например, когда вы устанавливаете скрытое состояние в false, вы не увидите внезапную видимость.

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)
    })
}
Shahriar
источник
Это решает проблему, которую другие спрашивали о том, где не работают фадеины. Умный подход.
BooTooMany
1

UIView.transition (с функцией :) хорош и аккуратен.

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

Вы можете полностью перевести скрытое свойство в true, тогда как при попытке перевести его в false, представление просто внезапно исчезнет без какой-либо анимации.

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

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

Чтобы решить эту проблему, при скрытии представления целью перехода должно быть его родительское представление вместо представления, которое вы хотите скрыть.

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)
}
ЛиЛи Казинэ
источник
0

Мое решение для Swift 3 . Итак, я создал функцию, которая скрывает / показывает вид в правильном порядке (при скрытии - установите альфа в 0, а затем isHidden в true; показать - сначала откройте представление, а затем установите его в 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блоке есть другая анимация, когда hideложь?
Джорджио
0

Swift 4 Transition

    UIView.transition(with: view, duration: 3, options: .transitionCurlDown,
                      animations: {
                        // Animations
                        view.isHidden = hidden
    },
                      completion: { finished in
                        // Compeleted
    })

Если вы используете подход для более старых версий Swift, вы получите ошибку:

Cannot convert value of type '(_) -> ()' to expected argument type '(() -> Void)?'

Полезная ссылка .

nanospeck
источник
это работает с autolayout? подобный код не анимирует. isHiddenзначение оказывается мгновенно (то есть, мгновенно скрытие / отображение).
Crashalot
0

Этот код дает анимацию, как нажатие viewController в контроллере uinavigation ...

CATransition *animation = [CATransition animation];
 animation.type = kCATransitionPush;
 animation.subtype = kCATransitionFromRight;
 animation.duration = 0.3;
 [_viewAccountName.layer addAnimation:animation forKey:nil];

 _viewAccountName.hidden = true;

Использовал это для поп-анимации ...

 CATransition *animation = [CATransition animation];
 animation.type = kCATransitionPush;
 animation.subtype = kCATransitionFromLeft;
 animation.duration = 0.3;
 [_viewAccountName.layer addAnimation:animation forKey:nil];

 _viewAccountName.hidden = false;
Prasanna
источник
0

Пробовал некоторые из вышедших ответов, некоторые работают только для одной ситуации, некоторые из них должны добавить две функции.

Опция 1

Ничего общего с 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
        })
    }
}

Затем пройти isFadeIn( trueили false)

view.animate(fadeIn: isFadeIn) 

Вариант 2

Не передавайте никаких параметров. Это исчезает или исчезает в соответствии с isUserInteractionEnabled. Это также очень хорошо подходит для анимации ситуации.

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
    })
}

Тогда вы звоните

yourView.animateFadeInOut()

Почему self.isUserInteractionEnabled?

Пытался заменить self.isUserInteractionEnabledна self.isHidden, не повезло вообще.

Вот и все. Стоит мне когда-нибудь, надеюсь, это кому-нибудь поможет.

Уильям Ху
источник