UIViewPropertyAnimator的使用

在iOS 10之前,執行動畫可以使用UIView以下三個類方法:

  • animateWithDuration: animations:
  • animateWithDuration: animations: completion:
  • animateWithDuration: delay: options: animations: completion:

上面創建動畫塊(animations: )的均是類方法,所以這些動畫塊沒有綁定任何視圖。因此,可以使用這些方法創建一個單一的動畫,應用于多個視圖。

下面代碼演示了在1秒鐘內淡出firstView、淡入secondView的操作。

    [UIView animateWithDuration:1.0 animations:^{
        self.firstView.alpha = 0.0;
        self.secondView.alpha = 1.0;
    }];

使用上述類方法操縱動畫過程中,firstViewsecondView兩個視圖將暫時禁用用戶交互,即用戶不能與正在運行動畫的視圖交互。如果想要實現更復雜的功能,需要使用CoreAnimation框架。雖然使用CoreAnimation框架可以對動畫進行暫停、恢復、停止等操作,但會產生大量代碼,需要大量工作,可以使用pop一類的第三方庫。

1. UIViewPropertyAnimator

在iOS 10,Apple在UIKit中增加了UIViewPropertyAnimator類,使用該類實現的動畫可以在結束前進行暫停、恢復、停止等操作。UIViewPropertyAnimator類對象通過操作視圖的屬性來產生所需動畫,但不是所有屬性的改變都會產生動畫,可產生動畫的屬性包括framecenteralphatransform

UIViewPropertyAnimator類遵守了UIViewAnimatingUIViewImplicitlyAnimating協議。UIViewAnimating協議中方法用于控制動畫的狀態,包括開始startAnimation、暫停pauseAnimation、結束stopAnimation:動畫,也有一些屬性用于反映當前動畫狀態。動畫運行時,這些狀態隨之更新。UIViewPropertyAnimator對象(后面稱為animator)在處理動畫期間會經歷UIViewAnimatingStateInactiveUIViewAnimatingStateActiveUIViewAnimatingStateStopped不同狀態。下圖顯示了animator狀態變化。

PropertyAnimatorState.png

Inactive狀態是animator的初始狀態。每一個新創建的animator均處于inactive狀態,animator在動畫結束后返回到inactive狀態。在非活躍狀態配置的動畫,其運行持續時間為指定的完整持續時間;使用addAnimations:方法添加的動畫,添加后立即開始執行,與其它動畫同時結束,即運行時間為剩余持續時間,非完整持續時間。

當調用startAnimationpauseAnimation方法后,animator變為active狀態。處于active狀態的animator可能正在運行動畫,也可能將動畫暫停,以便修改動畫。當動畫運行到指定位置結束后,animator將返回到inactive狀態,以便重新配置動畫。

調用stopAnimation:方法后,將停止所有正在運行的動畫,并將相應視圖屬性的值更新為調用stopAnimation:方法時的值。當stopAnimation:參數為YES時,animator狀態直接改變為UIViewAnimatingStateInactive,且不再執行任何動作;當stopAnimation:參數為NO時,animator狀態改變為UIViewAnimatingStateStopped,隨后,可以調用finishAnimationAtPosition:方法執行animator的最終動作。例如,執行completion塊。對finishAnimationAtPosition:方法的調用不是必須的,也可以在調用finishAnimationAtPosition:方法前先執行其它動畫。

UIViewImplicitlyAnimating協議用于在動畫進行過程中修改動畫,如添加動畫addAnimations:、添加completion塊addCompletion:等。

2. 示例1

下面通過一個demo來學習UIViewPropertyAnimator

創建Single View Application模板的應用,demo名稱為PropertyAnimator。在storyboard中添加一個UIView、三個UIButton、兩個UILabel、一個UISwitch、一個UIStepper和一個UISlider。布局如下:

PropertyAnimatorStoryboard.png

使用Auto Layout、Stack View對視圖進行自動布局,通過上圖可以看到所添加的約束,其中Stack View的spacing均為20。如果你對自動布局不熟悉,可以查看Auto Layout的使用Auto Layout中Stack View的使用兩篇文章。

storyboardViewController.m添加IBOutlet屬性。如下所示:

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIView *redView;
@property (weak, nonatomic) IBOutlet UIButton *restartButton;
@property (weak, nonatomic) IBOutlet UIButton *startStopButton;
@property (weak, nonatomic) IBOutlet UIButton *pauseButton;
@property (weak, nonatomic) IBOutlet UISwitch *reverseAnimationSwitch;
@property (weak, nonatomic) IBOutlet UIStepper *durationStepper;
@property (weak, nonatomic) IBOutlet UILabel *durationLabel;

@end

最后再添加以下三個屬性。

@interface ViewController ()

...
@property (strong, nonatomic) UIViewPropertyAnimator *propertyAnimator;
@property (assign, nonatomic) NSTimeInterval duration;
@property (assign, nonatomic) CGRect startFrame;

@end

現在添加一個setupAnimator的方法,用于配制動畫。

- (void)setupAnimator {
    // 1.動畫初始位置。
    self.redView.frame = self.startFrame;
    
    // 2.動畫終點位置。
    CGFloat margin = 16.0;
    CGFloat screenWidth = CGRectGetWidth(self.view.frame);
    CGFloat finalX = screenWidth - CGRectGetWidth(self.redView.frame) - margin;
    CGRect finalRect = CGRectMake(finalX, self.redView.frame.origin.y, self.redView.frame.size.width, self.redView.frame.size.height);
    
    // 3.初始化動畫。
    self.propertyAnimator = [[UIViewPropertyAnimator alloc] initWithDuration:self.duration
                                                                       curve:UIViewAnimationCurveEaseIn
                                                                  animations:^{
                                                                      self.redView.frame = finalRect;
                                                                  }];
    
    // 4.為動畫添加完成塊。
    ViewController * __weak weakSelf = self;
    ViewController *vc = weakSelf;
    if (vc) {
        [self.propertyAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
            [vc.startStopButton setTitle:@"Start" forState:UIControlStateNormal];
            vc.startStopButton.enabled = NO;
            vc.pauseButton.enabled = NO;
            vc.restartButton.enabled = YES;
        }];
    }
    vc = nil;
}

在上面的代碼中,注釋3部分用于初始化動畫,其中initWithDuration:的參數為動畫持續時間;curve:參數用來設定動畫曲線。這里有以下四種可選曲線:

  • UIViewAnimationCurveEaseInOut:這種曲線的動畫開始緩慢,在其持續時間的中間加速,然后在完成之前再次減慢。這是大多數動畫的默認曲線。
  • UIViewAnimationCurveEaseIn:動畫開始時緩慢,然后加速,直到動畫結束。這里選用這種類型動畫曲線。
  • UIViewAnimationCurveEaseOut:動畫開始時速度很快,在結束前開始減速。
  • UIViewAnimationCurveLinear:在動畫持續時間內,動畫勻速運行。

最后在動畫塊內配置動畫。注釋4部分,為動畫塊添加完成回調函數。這里需要注意避免形成循環引用,使用__weak聲明的weakSelf替代self,因為塊內多次用到weakSelf,可能在第一次調用weakSelfweakSelf存在,但后面再次調用weakSelf時,weakSelf已被釋放,所以這里再次將其轉換為強引用類型vc,不再需要vc時,需要手動釋放。

想要了解更多關于塊的用法,查看Block的用法一文。

storyboard中選中UIStepper控件,拖拽到代碼中,以添加響應事件。

- (IBAction)stepperValueChanged:(UIStepper *)sender {
    // 1.設置動畫持續時間為UIStpper的值。
    self.duration = sender.value;
    
    // 2.同步更新到label。
    self.durationLabel.text = [NSString stringWithFormat:@"%.1f",sender.value];
}

上述代碼用于設定動畫持續時間。

storyboard中選中Start按鈕,拖拽到ViewController.m實現部分,以添加響應事件,響應事件方法名稱為startStopPause。在storyboard中選中Pause按鈕,也拖拽到startStopPause:響應事件,以便在點擊StartPause任一按鈕時,均調用startStopPause:方法。

- (IBAction)startStopPause:(UIButton *)sender {
    // 1.禁用restartButton,propertyAnimator不存在時,配置propertyAnimator。
    self.restartButton.enabled = NO;
    if (!self.propertyAnimator) {
        [self setupAnimator];
    }
    
    if (sender == self.pauseButton) {
        // 2.點擊Pause按鈕時,根據當前動畫狀態更新視圖。
        self.propertyAnimator.isRunning ? [self.propertyAnimator pauseAnimation] : [self.propertyAnimator startAnimation];
        NSString *title = self.propertyAnimator.isRunning ? @"Pause" : @"Unpause";
        [self.pauseButton setTitle:title forState:UIControlStateNormal];
        self.startStopButton.enabled = self.propertyAnimator.isRunning;
    }
    else
    {
        // 3.點擊Start按鈕時,根據當前動畫狀態更新視圖。
        switch (self.propertyAnimator.state) {
            case UIViewAnimatingStateInactive:
                [self.propertyAnimator startAnimation];
                [self.startStopButton setTitle:@"Stop" forState:UIControlStateNormal];
                self.pauseButton.enabled = YES;
                NSLog(@"UIViewAnimatingStateInactive");
                break;
                
            case UIViewAnimatingStateActive:
                if (self.propertyAnimator.isRunning) {
                    [self.propertyAnimator stopAnimation:NO];
                    [self.propertyAnimator finishAnimationAtPosition:UIViewAnimatingPositionCurrent];
                    [self.startStopButton setTitle:@"Start" forState:UIControlStateNormal];
                    self.pauseButton.enabled = NO;
                }
                else
                {
                    [self.propertyAnimator startAnimation];
                    [self.startStopButton setTitle:@"Stop" forState:UIControlStateNormal];
                    self.pauseButton.enabled = YES;
                }
                NSLog(@"UIViewAnimatingStateActive");
                break;
                
            case UIViewAnimatingStateStopped:
                NSLog(@"UIViewAnimatingStateStopped");
                break;
                
            default:
                break;
        }
    }
}

上面代碼根據所點擊的按鈕,進行不同的響應操作。當點擊的是Start按鈕時,根據propertyAnimator所處的狀態執行不同操作。

storyboard中拖拽UISwitch控件到代碼中,以創建響應事件。

- (IBAction)reverseAnimationSwitchValueChanged:(UISwitch *)sender {
    if (self.propertyAnimator && self.propertyAnimator.isRunning) {
        // 在propertyAnimator存在,且正在運行時,根據UISwitch的值調整propertyAnimator的方向。
        self.propertyAnimator.reversed = sender.isOn;
    }
}

storyboard中拖拽Restart Animation按鈕到代碼中,以創建響應事件。

- (IBAction)restartAnimation:(UIButton *)sender {
    // 點擊RestartAnimation按鈕時,重新配置動畫,啟用Start按鈕,將reverseAnimationSwitch設置為關閉狀態。
    [self setupAnimator];
    self.startStopButton.enabled = YES;
    self.reverseAnimationSwitch.on = NO;
}

可以通過為fractionComplete屬性賦值,設置動畫進度百分比。從storyboard中拖拽UISlider控件到代碼中,創建響應事件。

- (IBAction)scrubAnimation:(UISlider *)sender {
    if (!self.propertyAnimator) {
        [self setupAnimator];
    }
    
    // 1.當propertyAnimator正在運行時,暫停該動畫,否則在停止拖動UISlider后,動畫會繼續運行。
    if (self.propertyAnimator.isRunning) {
        [self.propertyAnimator pauseAnimation];
    }
    
    // 2.設置動畫百分比。
    self.propertyAnimator.fractionComplete = sender.value;
}

最后,記得設置startFrame位置、pauseButton初始狀態。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 設置startFrame位置,pauseButton狀態。
    self.startFrame = CGRectMake(16, 45, 100, 100);
    self.pauseButton.enabled = NO;
}

現在運行demo,效果如下。

PropertyAnimatorAnimator.gif

3. 示例2

UIViewPropertyAnimator除了可以使用原有的UIViewAnimationCurve時間曲線函數,還新增了UISpringTimingParametersUICubicTimingParameters兩個時間曲線函數。

添加Cocoa Touch Class模版的文件,其父類為UIViewController,名稱為TimingCurvesViewController。在storyboard中添加UIViewController,并設置其父類為TimingCurvesViewController

在剛添加的視圖控制器上添加四個UIView、四個UILabel。同時選中兩個視圖控制器,添加UITabBarController,如下所示:

PropertyAnimatorCurve.png

TimingCurvesViewController上的UIView創建IBOutlet連接,并添加以下幾個屬性。

#import "TimingCurvesViewController.h"

@interface TimingCurvesViewController ()

@property (weak, nonatomic) IBOutlet UIView *redView;
@property (weak, nonatomic) IBOutlet UIView *blueView;
@property (weak, nonatomic) IBOutlet UIView *greenView;
@property (weak, nonatomic) IBOutlet UIView *yellowView;
@property (assign, nonatomic) CGRect redStartFrame;
@property (assign, nonatomic) CGRect blueStartFrame;
@property (assign, nonatomic) CGRect greenStartFrame;
@property (assign, nonatomic) CGRect yellowStartFrame;
@property (strong, nonatomic) UIViewPropertyAnimator *redAnimator;
@property (strong, nonatomic) UIViewPropertyAnimator *blueAnimator;
@property (strong, nonatomic) UIViewPropertyAnimator *greenAnimator;
@property (strong, nonatomic) UIViewPropertyAnimator *yellowStartAnimator;
@property (strong, nonatomic) NSTimer *timer;
@property (assign, nonatomic) NSTimeInterval durationOfAnimation;

@end

TimingCurvesViewController.mviewDidLoad方法中,設置四個UIView的初始位置和durationOfAnimation值。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1.設置UIView初始位置。
    self.redStartFrame = CGRectMake(16, 50, squareSize, squareSize);
    self.blueStartFrame = CGRectMake(16, 150, squareSize, squareSize);
    self.greenStartFrame = CGRectMake(16, 250, squareSize, squareSize);
    self.yellowStartFrame = CGRectMake(16, 350, squareSize, squareSize);
    
    // 2.為durationOfAnimation賦初始值2.0。
    self.durationOfAnimation = 2.0;
}

3.1 UIViewAnimationCurve

UIViewAnimationCurve時間曲線函數分為UIViewAnimationCurveEaseInOutUIViewAnimationCurveEaseInUIViewAnimationCurveEaseOutUIViewAnimationCurveLinear四種。

TimingCurvesViewController.m實現部分添加以下代碼來使用上述四種時間曲線。

// Default Curves
- (void)startAnimationsWithDefaultCurves {
    // 1.四個視圖使用不同類型時間曲線函數。
    self.redAnimator = [self animatorForView:self.redView startFrame:self.redStartFrame curve:UIViewAnimationCurveLinear];
    self.blueAnimator = [self animatorForView:self.blueView startFrame:self.blueStartFrame curve:UIViewAnimationCurveEaseIn];
    self.greenAnimator = [self animatorForView:self.greenView startFrame:self.greenStartFrame curve:UIViewAnimationCurveEaseOut];
    self.yellowAnimator = [self animatorForView:self.yellowView startFrame:self.yellowStartFrame curve:UIViewAnimationCurveEaseInOut];
}

- (UIViewPropertyAnimator *)animatorForView:(UIView *)view startFrame:(CGRect)startFrame curve:(UIViewAnimationCurve)curve {
    // 2.視圖初始位置,動畫結束時視圖位置。
    view.frame = startFrame;
    CGRect finalRect = [self finalRectWithStartFrame:startFrame];
    
    // 3.配置動畫。
    UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc] initWithDuration:self.durationOfAnimation curve:curve animations:^{
        view.frame = finalRect;
    }];
    return animator;
}

#pragma mark Help Methods

- (CGRect)finalRectWithStartFrame:(CGRect)startFrame {
    // 4.計算出動畫結束時位置。
    CGFloat margin = 16;
    CGFloat screenWidth = CGRectGetWidth(self.view.frame);
    CGFloat finalX = screenWidth - margin - squareSize;
    CGRect finalRect = CGRectMake(finalX, startFrame.origin.y, squareSize, squareSize);
    return finalRect;
}

上述代碼非常簡單,在注釋1部分使用UIViewAnimationCurveLinearUIViewAnimationCurveEaseInUIViewAnimationCurveEaseOutUIViewAnimationCurveEaseInOut四種時間曲線。注釋4的方法后面會多次用到。

TimingCurvesViewController.m實現部分添加viewDidAppear:方法,用定時器觸發動畫。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    // 1.在1.5倍durationOfAnimation時間后,觸發動畫。
    self.timer = [NSTimer scheduledTimerWithTimeInterval:self.durationOfAnimation*1.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        // 2.動畫使用默認時間曲線函數。
        [self startAnimationsWithDefaultCurves];
        
        // 啟動動畫。
        [self.redAnimator startAnimation];
        [self.blueAnimator startAnimation];
        [self.greenAnimator startAnimation];
        [self.yellowAnimator startAnimation];
    }];
}

如果使用標準方法(initWith方法)創建動畫,必須通過調用startAnimation方法開始動畫;如果想要創建動畫后立即開始執行動畫,請使用runningPropertyAnimatorWithDuration: delay: options: animations: completion:方法。

運行demo,如下所示:

PropertyAnimatorDefaultCurves.gif

通過上面代碼可以看到:

  • UIViewAnimationCurveEaseInOut:這種曲線的動畫開始緩慢,在其持續時間的中間加速,然后在完成之前再次減慢。這是大多數動畫的默認曲線。
  • UIViewAnimationCurveEaseIn:動畫開始時緩慢,然后加速,直到動畫結束。
  • UIViewAnimationCurveEaseOut:動畫開始時速度很快,在結束前開始減速。
  • UIViewAnimationCurveLinear:在動畫持續時間內,動畫勻速運行。

3.2 UICubicTimingParameters

UICubicTimingParameters允許通過多個控制點來定義三階貝塞爾曲線,該貝塞爾時間曲線起點為(0,0),終點為(1,1),曲線形狀由兩個控制點決定。每個時間點線的斜率定義了此時動畫速度。曲線越陡峭,動畫運行速度越快;曲線越平緩,動畫運行速度越慢。

下圖的時間曲線表示動畫在開始和結束時速度很快,中間運行較慢。

PropertyAnimatorCubicTiming.png

控制點范圍為0.0至1.0。

UICubicTimingParameters遵守UITimingCurveProvider協議,為遵守UIViewAnimating協議的對象提供時間曲線(timing curves),如UIViewPropertyAnimator

繼續更新TimingCurvesViewController.m內代碼,使用UICubicTimingParameters作為動畫時間參數。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    // 1.在1.5倍durationOfAnimation時間后,觸發動畫。
    self.timer = [NSTimer scheduledTimerWithTimeInterval:self.durationOfAnimation*1.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        // 2.動畫使用默認時間曲線函數。
//        [self startAnimationsWithDefaultCurves];
        
        // 3.使用UICubicTimingParameters
        [self startAnimationWithCubicCurves];
        
        // 啟動動畫。
        [self.redAnimator startAnimation];
        [self.blueAnimator startAnimation];
        [self.greenAnimator startAnimation];
        [self.yellowAnimator startAnimation];
    }];
}

// UICubicTimingParameters
- (void)startAnimationWithCubicCurves {
    // 1.中間慢,開始、結尾快。
    UICubicTimingParameters *redCubicTimingParameters = [[UICubicTimingParameters alloc] initWithControlPoint1:CGPointMake(0.45, 1.0) controlPoint2:CGPointMake(0.55, 0)];
    // 2.中間快,開始、結尾慢。
    UICubicTimingParameters *blueCubicTimingParameters = [[UICubicTimingParameters alloc] initWithControlPoint1:CGPointMake(1.0, 0.45) controlPoint2:CGPointMake(0, 0.55)];
    self.redAnimator = [self animatorForView:self.redView startFrame:self.redStartFrame timingParameters:redCubicTimingParameters];
    self.blueAnimator = [self animatorForView:self.blueView startFrame:self.blueStartFrame timingParameters:blueCubicTimingParameters];
}

- (UIViewPropertyAnimator *)animatorForView:(UIView *)view startFrame:(CGRect)startFrame timingParameters:(UICubicTimingParameters *)cubicTimingParameters {
    view.frame = startFrame;
    CGRect finalRect = [self finalRectWithStartFrame:startFrame];
    UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc] initWithDuration:self.durationOfAnimation timingParameters:cubicTimingParameters];
    [animator addAnimations:^{
        view.frame = finalRect;
    }];
    return animator;
}

其中,startAnimationWithCubicCurves方法內,注釋1中的控制點決定動畫曲線,動畫在中間慢,開始和結尾處快。注釋2相反。這里只使用了redViewblueView兩個視圖。

運行如下:

PropertyAnimatorCubicParameters.gif

3.3 UISpringTimingParameters

UISpringTimingParameters提供的時間曲線會讓動畫行為與彈簧相似。視圖會加速向目標點運動,然后圍繞該目標點震蕩,直到停止。

UISpringTimingParameters遵守UITimingCurveProvider協議,為遵守UIViewAnimating協議的對象提供時間曲線,如UIViewPropertyAnimatorUISpringTimingParameters一般用于移動屏幕上的視圖,也可用于視圖的其它屬性,以獲取類似的動畫效果。

繼續更新TimingCurvesViewController.m內代碼,使用UISpringTimingParameters作為動畫運行時間參數。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    // 1.在1.5倍durationOfAnimation時間后,觸發動畫。
    self.timer = [NSTimer scheduledTimerWithTimeInterval:self.durationOfAnimation*1.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        // 2.動畫使用默認時間曲線函數。
//        [self startAnimationsWithDefaultCurves];
        
        // 3.使用UICubicTimingParameters。
//        [self startAnimationWithCubicCurves];
        
        // 4.使用UISpringTimingParameters。
        [self startAnimationWithSpringCurves];
        
        // 啟動動畫。
        [self.redAnimator startAnimation];
        [self.blueAnimator startAnimation];
        [self.greenAnimator startAnimation];
        [self.yellowAnimator startAnimation];
    }];
}

// UISpringTimingParameters
- (void)startAnimationWithSpringCurves {
    // dampingRatio值分別為0.2 1.0 2.0。
    CGFloat underDamped = 0.2;
    CGFloat criticalDamped = 1.0;
    CGFloat overDamped = 2.0;
    self.redAnimator = [self animatorForView:self.redView startFrame:self.redStartFrame dampingRatio:underDamped];
    self.blueAnimator = [self animatorForView:self.blueView startFrame:self.blueStartFrame dampingRatio:criticalDamped];
    self.greenAnimator = [self animatorForView:self.greenView startFrame: self.greenStartFrame dampingRatio:overDamped];
}

- (UIViewPropertyAnimator *)animatorForView:(UIView *)view startFrame:(CGRect)startFrame dampingRatio:(CGFloat)dampingRatio {
    view.frame = startFrame;
    CGRect finalRect = [self finalRectWithStartFrame:startFrame];
    UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc] initWithDuration:self.durationOfAnimation dampingRatio:dampingRatio animations:^{
        view.frame = finalRect;
    }];
    return animator;
}

另外,也可以使用initWithMass: stiffness: damping: initialVelocity:方法,該方法會把阻尼系數(damping)、質量參數(mass)、剛性系數(stiffness)和初始速度(initial velocity)帶入給定公式,以獲取更為真實的效果。

運行demo,如下所示:

PropertyAnimatordampingRatio.gif

UIDynamicAnimator中的UISnapBehavior也可以產生彈簧(spring)效果,UISnapBehavior是移動到指定點point,如下圖所示。想要全面了解UIKitDynamicAnimator,可以查看一篇文章學會使用UIKit Dynamics

Dynamics4UISnapBehavior.gif

Demo名稱:PropertyAnimator
源碼地址:https://github.com/pro648/BasicDemos-iOS

參考資料:

  1. iOS10 – UIViewPropertyAnimator
  2. iOS 10 Day by Day :: Day 4 :: UIViewPropertyAnimator
  3. QUICK GUIDE: ANIMATIONS WITH UIVIEWPROPERTYANIMATOR

歡迎更多指正:https://github.com/pro648/tips/wiki

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,232評論 4 61
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,284評論 25 708
  • 看題目就知道我偷懶了好久,上次日日更的時候已經是兩個月前了。這三個月我做了很多事情,也忘記了很多事情,于是現在就讓...
    killerking閱讀 233評論 0 0
  • 有句話說,找男(女)友千萬不要找能減肥成功的人,他們非常可怕,他們無情,他們有鋼鐵般的意志。 但我認為,能減肥,證...
    方老司閱讀 367評論 0 1
  • 幸運的時候一定要努力,因為風水輪流轉,不幸的時候一定要堅持,因為柳岸花明又一村。我的全部安全感都來自于想做的事,我...
    蒙味集APP閱讀 226評論 0 0