UIViewアニメーションで非表示/表示


154

私の単純な目標は、アニメーションの非表示および表示機能をフェードインすることです。

Button.hidden = YES;

十分に単純です。しかし、単に消えるのではなく、フェードアウトさせることは可能ですか?そのようにそれはかなり専門外に見えます。

回答:


259

iOS 4以降では、QuartzCoreをインポートする必要なく、UIView遷移メソッドを使用するだけでこれを行う方法があります。あなたはただ言うことができます:

目的C

[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;Michailが回答で提供したアルファアニメーションコードを設定して使用します。これにより、レイヤーが奇妙にブレンドするのを防ぎますが、パフォーマンスがわずかに低下し、ボタンがピクセル境界に正確に配置されていないと、ボタンがぼやけて見える場合があります。

または:

2)代わりに次のコードを使用してフェードをアニメーション化します。

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

button.hidden = YES;

このアプローチの良いところは、アニメーション化できないボタンのプロパティ(ボタンのテキストや画像など)でもクロスフェードでき、トランジションを設定して、すぐにプロパティを設定できることです。


5
@robmathers、私はあなたのコードをテストします、上の2つのコードは、button.hidden = NOのときに機能し、フェードインの状況になります。button.hidden = YESの場合、フェードアウトのアニメーション効果はありません。
Jason

iOS 12.0で壊れているようです
user3532505 '15

5
transitionWithViewフェードインとフェードアウトを確実に成功させるには、アニメーション化するもののスーパービューをパラメーターとして使用する必要があります。
アレン

159

UIViewアニメーションプロパティは次のとおりです。

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

説明: アニメーション

isHidden それはそれらの1つではないので、私がそれを見ると、最良の方法は次のとおりです。

スウィフト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];
}

8
実はこれは簡単で、最良の答えである
Irshadモハメド

3
これは正しくアニメーション化されますが、表示しようとしているUISearchBarは、アニメーションが完了してすぐに正しい位置にジャンプするまで、間違った場所に表示されます。何か案が?ストーリーボードとインターフェイスビルダーおよび制約を使用しています。
グレッグヒルストン2017年

5
このコードは機能しません...アニメーション化せずに直接状態を変更します
Mihir Mehta

2
@evya非表示の場合はフェードインでのみ機能します= NO、フェードアウトでは機能しません。非表示= YES
Jason

驚くばかり。多くの10倍
Vyacheslav

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

スウィフト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;
}];

スウィフト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
}

非表示状態と組み合わせてフェードイン/フェードアウトを使用すると、私の問題が解決しました
ACLima

何らかの理由で、hidden = YESへのアニメーション化は私にとってはうまくいきましたが、hidden = NOへのアニメーション化は何もしなかったため、アルファのアニメーション化と非表示プロパティの設定のこの組み合わせは役に立ちました。
arlomedia 2017

私はデモを書いているだけですが、非表示=いいえ、フェードイン、奇妙です
Jason

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

スウィフト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
     })
}

7

迅速な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ます。
Mike Taverne

6

UIViewこの目的のためにカテゴリを作成し、特別な少し異なる概念を実装しました:visibility。私のソリューションの主な違いは、あなたが呼び出すことができ[view setVisible:NO animated:YES]、その直後に同期的にチェックできることです[view visible]し、正しい結果を得る。これはかなりシンプルですが、非常に便利です。

また、「負のブールロジック」の使用を回避することもできます(詳細については、 コード完了、ページ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バージョンは来ていますか?
Juan Boero 2016年

承知しました!Swift版を追加しました。
Valentin Shergin 16

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

スウィフト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の回答をコピーしました
Ashley Mills

違いがあります、彼は見解を隠していませんでした。また、ビューも非表示にする必要がありました。そうしてそれを共有しました。
Umair Afzal

3
それをコピーしてあなた自身のものとして渡すのではなく、他の答えにコメントしてみませんか?
Ashley Mills

2

isHidden 即値であり、アニメーションに影響を与えることはできません。これの代わりに、アルファを使用してビューを非表示にすることができます

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

1

ビューがデフォルトで非表示に設定されている場合、または多くの場合に必要と思われる非表示の状態を変更した場合、このページのどのアプローチもFadeIn / FadeOutアニメーションの両方を提供せず、これらの状態の1つのみをアニメーション化します。その理由は、UIView.animateメソッドを呼び出す前にHidden状態をfalseに設定しているため、突然の可視性が発生し、アルファのみをアニメーション化した場合、オブジェクトスペースはまだそこにありますが、表示されないため、UIの問題が発生します。

したがって、最善の方法は、最初にビューが非表示かどうかを確認してから、アルファを0.0に設定することです。このように、Hidden状態を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)
    })
}

これにより、フェードインが機能しない場所について他の人が質問した問題が解決されます。賢いアプローチ。
BooTooMany

1

UIView.transition(with :)関数は素晴らしく、きちんとしています。

多くの人がそれを投稿しましたが、実行したときにのみ障害が表示されることに気づく人はいません。

hiddenプロパティを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)
}

falseのcompletionときに、ブロック内に別のアニメーションがあるのはなぜhideですか?
ジョルジオ

0

Swift 4への移行

    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)?'

便利なリファレンス


これは自動レイアウトで機能しますか?同様のコードはアニメーション化されていません。isHidden値(すなわち、瞬時ビューを示す/隠す)即座にレンダリングされます。
Crashalot 2017年

0

このコードは、uinavigationコントローラーでviewControllerを押すようなアニメーションを提供します...

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;

0

終了した回答のいくつかを試しましたが、一部は1つの状況でのみ機能し、一部は2つの関数を追加する必要があります。

オプション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
        })
    }
}

次にisFadeIntrueまたは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、まったく運がありませんでした。

それでおしまい。いつか私を犠牲にして、それが誰かを助けることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.