iOS 動(dòng)畫(huà)篇 - UIKit動(dòng)畫(huà)(二)

簡(jiǎn)單使用篇

簡(jiǎn)介

iOS10帶來(lái)了很多新特性,其中有個(gè) UIViewPropertyAnimator 類(lèi)烈炭,光從名字上就可以看出,這是一個(gè)操作屬性動(dòng)畫(huà)的類(lèi)宝恶。實(shí)際上符隙,這個(gè)類(lèi)能夠讓我們對(duì)視圖進(jìn)行動(dòng)畫(huà)控制趴捅,我們除了可進(jìn)行正常的運(yùn)行動(dòng)畫(huà),如開(kāi)始霹疫、暫停拱绑、重啟等操作動(dòng)畫(huà),還可以將動(dòng)畫(huà)轉(zhuǎn)換為交互式動(dòng)畫(huà)丽蝎,任意的控制時(shí)間猎拨。

它可以對(duì)視圖的可動(dòng)畫(huà)屬性進(jìn)行操作,例如frame屠阻,center红省,alpha 和 transform等,并且可以任意的添加多個(gè)動(dòng)畫(huà)塊和完成塊国觉,相比于之前的 UIView 動(dòng)畫(huà)吧恃,它改變了我們習(xí)慣的動(dòng)畫(huà)流程,變得更加靈活麻诀。

簡(jiǎn)單例子

改變一個(gè)視圖的 center 動(dòng)畫(huà):

// 創(chuàng)建動(dòng)畫(huà)器
UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0
                                                                              curve:UIViewAnimationCurveEaseOut
                                                                         animations:^{
    self.contentView.center = self.view.center;
}];
// 開(kāi)始動(dòng)畫(huà)
[animator startAnimation];
移動(dòng)位置的動(dòng)畫(huà)

在使用 UIViewPropertyAnimator 做動(dòng)畫(huà)時(shí)痕寓,需要關(guān)注下面幾個(gè)點(diǎn):

  • 包含改變一個(gè)或多個(gè)視圖屬性的動(dòng)畫(huà)塊
  • 用于定義動(dòng)畫(huà)運(yùn)行過(guò)程中的時(shí)間速率曲線(xiàn)
  • 動(dòng)畫(huà)的持續(xù)時(shí)間(以秒為單位)
  • 動(dòng)畫(huà)完成塊(可選)

在上面的簡(jiǎn)單實(shí)例中,我們?cè)?秒的時(shí)間內(nèi)针饥,改變了視圖的中心位置厂抽,其中動(dòng)畫(huà)塊即為 animations 的代碼塊,在此代碼塊中我們可以針對(duì)可動(dòng)動(dòng)規(guī)劃進(jìn)行新增改變丁眼。對(duì)于運(yùn)行的動(dòng)畫(huà)時(shí)間速率筷凤,動(dòng)畫(huà)器 animator 支持 UIKit 動(dòng)畫(huà)中的時(shí)間速率函數(shù),即linear苞七、ease-in藐守、ease-out等。

一般來(lái)說(shuō)蹂风,我們所創(chuàng)建的動(dòng)畫(huà)器都是處于非活躍狀態(tài)卢厂,需要手動(dòng)調(diào)用-startAnimation將其變?yōu)榛钴S狀態(tài)執(zhí)行動(dòng)畫(huà)。

初始化動(dòng)畫(huà)器

UIViewPropertyAnimator 為我們提供了多個(gè)快捷創(chuàng)建動(dòng)畫(huà)器的方法惠啄。

  • 使用內(nèi)置時(shí)間速率函數(shù)

-initWithDuration:curve:animations:

這種方式就是我們節(jié)例子中的使用到的創(chuàng)建方法慎恒,curve 參數(shù)即時(shí)間速率函數(shù),其所支持的以下幾種:

UIViewAnimationCurveEaseInOut //緩進(jìn)緩出
UIViewAnimationCurveEaseIn //緩進(jìn)
UIViewAnimationCurveEaseOut //緩出
UIViewAnimationCurveLinear //線(xiàn)性勻速
四種內(nèi)置時(shí)間速率

如果所說(shuō) UIKit 提供的速率曲線(xiàn)函數(shù)不能夠滿(mǎn)足你的執(zhí)行動(dòng)畫(huà)的速率要求撵渡,你還可以通過(guò)自定義來(lái)創(chuàng)建自己的速度曲線(xiàn)融柬。

  • 使用三次貝塞爾曲線(xiàn)

-initWithDuration:controlPoint1:controlPoint2:animations:

三次貝塞爾曲線(xiàn)的起點(diǎn)為(0,0)且其終點(diǎn)為(1,1),因此兩個(gè)控制點(diǎn)的取值范圍是(0,1)趋距。

  • 使用基于彈簧的彈性

-initWithDuration:dampingRatio:animations:

dampingRatio:所對(duì)應(yīng)的參數(shù)叫做阻尼粒氧,一般去值為(0,1)較低的阻尼值對(duì)應(yīng)較小阻力和在靜止之前更多更大的振蕩节腐。反之則阻力大外盯,振蕩少而小摘盆。例如你想不振蕩的情況下平滑的減速動(dòng)畫(huà),就可以指定值為1饱苟。

// 創(chuàng)建動(dòng)畫(huà)器
UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0
                                                                       dampingRatio:0.35
                                                                         animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}];
// 開(kāi)始動(dòng)畫(huà)
[animator startAnimation];
彈性動(dòng)畫(huà)
  • 使用自定義時(shí)間速率對(duì)象

-initWithDuration:timingParameters:

該方法需要你提供支持 UITimingCurveProvider 協(xié)議的對(duì)象孩擂,如果你要自定義實(shí)現(xiàn)此協(xié)議,必須提供所有屬性的實(shí)現(xiàn)掷空。

系統(tǒng)有兩個(gè)遵循該協(xié)議的類(lèi)

UICubicTimingParameters 
UISpringTimingParameters

如果你查看UICubicTimingParameters類(lèi)時(shí)肋殴,你會(huì)發(fā)現(xiàn),這個(gè)類(lèi)也只是提供了支持 UIKit 內(nèi)置的時(shí)間速率曲線(xiàn)和三次貝塞爾曲線(xiàn)坦弟。類(lèi)似的UISpringTimingParameters也提供了CASpringAnimation中的幾個(gè)物理參數(shù)。

示例:我們通過(guò)該方法實(shí)現(xiàn)一下和上一個(gè)方法類(lèi)似的效果

// 彈性的時(shí)間速率
UISpringTimingParameters* parameters = [[UISpringTimingParameters alloc] initWithDampingRatio:0.35];
// 創(chuàng)建動(dòng)畫(huà)器
UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0 timingParameters:parameters];
// 由于該創(chuàng)建方法沒(méi)有動(dòng)畫(huà)塊官地,因此需要自行追加
[animator addAnimations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}];
// 開(kāi)始動(dòng)畫(huà)
[animator startAnimation];
彈性的時(shí)間速率

如果說(shuō)酿傍,你受不了每次都需要主動(dòng)調(diào)用-startAnimation方法來(lái)啟動(dòng)視圖動(dòng)畫(huà),還是習(xí)慣 UIView 的快捷使用驱入!??赤炒,蘋(píng)果似乎注意到了這一點(diǎn),為了適應(yīng)開(kāi)發(fā)者的習(xí)慣亏较,除了上述幾種創(chuàng)建動(dòng)畫(huà)器的方式莺褒,還有一種可以啟動(dòng)開(kāi)啟動(dòng)畫(huà)并能返回當(dāng)前動(dòng)畫(huà)器的方法。

  • 類(lèi)方法便捷創(chuàng)建

+ runningPropertyAnimatorWithDuration:delay:options:animations:completion:

該方法提供了動(dòng)畫(huà)的幾個(gè)相對(duì)比較重要的參數(shù)雪情,如動(dòng)畫(huà)執(zhí)行時(shí)間遵岩、延遲時(shí)間、時(shí)間速率巡通、動(dòng)畫(huà)塊尘执、完成塊。該方法兼容了 UIView 動(dòng)畫(huà)塊的形式宴凉。

[UIViewPropertyAnimator runningPropertyAnimatorWithDuration:1.0
                                                      delay:0
                                                    options:UIViewAnimationCurveEaseOut
                                                 animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}
                                                 completion:^(UIViewAnimatingPosition finalPosition) {}];
快捷使用

控制動(dòng)畫(huà)

UIViewPropertyAnimator 遵守了 UIViewImplicitlyAnimating 協(xié)議誊锭,而UIViewImplicitlyAnimating 協(xié)議是 UIViewAnimating 協(xié)議的子類(lèi),該類(lèi)定義了如何控制動(dòng)畫(huà)的協(xié)議弥锄。除了上一節(jié)中使用到的-startAnimation方法丧靡,還有其他幾個(gè)控制動(dòng)畫(huà)的方法。

  • 開(kāi)始執(zhí)行動(dòng)畫(huà)

-startAnimation:方法可以啟動(dòng)動(dòng)畫(huà)或者在暫停動(dòng)畫(huà)后恢復(fù)動(dòng)畫(huà)籽暇。
-startAnimationAfterDelay::和上面方法類(lèi)似温治,不過(guò)可以指定延遲執(zhí)行的時(shí)間

  • 暫停動(dòng)畫(huà)

-pauseAnimation:暫停動(dòng)畫(huà),當(dāng)使用該方法后图仓,動(dòng)畫(huà)會(huì)停留在“當(dāng)前位置”罐盔,會(huì)保持當(dāng)前的狀態(tài)。暫停后可以使用-startAnimation恢復(fù)救崔,恢復(fù)的動(dòng)畫(huà)會(huì)從“當(dāng)前位置”繼續(xù)剩余的動(dòng)畫(huà)惶看,包括剩余的時(shí)間捏顺。

示例:我們執(zhí)行一個(gè)2秒時(shí)長(zhǎng)的動(dòng)畫(huà),在1秒處停止纬黎,延遲1秒后恢復(fù)動(dòng)畫(huà)幅骄,讓其繼續(xù)執(zhí)行。

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:2.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
} completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 暫停當(dāng)前動(dòng)畫(huà)
    [animator pauseAnimation];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 恢復(fù)動(dòng)畫(huà)
        [animator startAnimation];
    });
});
動(dòng)畫(huà)的暫停和恢復(fù)
  • -stopAnimation::停止動(dòng)畫(huà)

停止動(dòng)畫(huà)有多種情況本今,由于動(dòng)畫(huà)狀態(tài)的機(jī)制(進(jìn)階篇會(huì)講)的存在拆座,當(dāng)我們停止動(dòng)畫(huà)后,這些動(dòng)畫(huà)狀態(tài)信息何去何從冠息?蘋(píng)果給出了兩種的去處挪凑,一種時(shí)清除所有狀態(tài)信息,動(dòng)畫(huà)器重置為初始的非活躍狀態(tài)逛艰,以等待下一個(gè)動(dòng)畫(huà)躏碳;另外一種是保留所有狀態(tài)信息,等待下一步操作散怖。這里的 withoutFinishing 參數(shù)就是用來(lái)指明去處菇绵。

參數(shù) withoutFinishing,表示是否應(yīng)執(zhí)行任何最終操作镇眷。如果值為 YES咬最,則會(huì)清除任何動(dòng)畫(huà)并將動(dòng)畫(huà)器重置為非活躍狀態(tài),并且不會(huì)執(zhí)行完成塊的回調(diào)欠动。

示例:我們執(zhí)行一個(gè)2秒的動(dòng)畫(huà)永乌,在一秒處停止當(dāng)前動(dòng)畫(huà),并且在完成塊中將視圖的背景色更改為紅色翁垂。

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:2.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
} completion:^(UIViewAnimatingPosition finalPosition) {
    // 動(dòng)畫(huà)的完成回調(diào)
    self.contentView.backgroundColor = UIColor.redColor;
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [animator stopAnimation:YES];
});
withoutFinishing為YES的情況

運(yùn)行結(jié)果發(fā)現(xiàn)铆遭,動(dòng)畫(huà)在1秒處停止了,但是并沒(méi)變成紅色背景沿猜,這說(shuō)明枚荣,此時(shí)的動(dòng)畫(huà)器并不會(huì)執(zhí)行完成塊。

當(dāng)參數(shù)為 NO 時(shí)啼肩,動(dòng)畫(huà)器狀態(tài)為 stopped橄妆,此時(shí)通常會(huì)配合finishAnimationAtPosition:使用,該方法可以幫助動(dòng)畫(huà)器執(zhí)行最終的完成塊的內(nèi)容祈坠,當(dāng)然害碾,這兩個(gè)方法的目的是停下當(dāng)前動(dòng)畫(huà),讓你完成此刻需要完成的內(nèi)容赦拘,如其他動(dòng)畫(huà)慌随,之后,你再使用finishAnimationAtPosition:完成動(dòng)畫(huà)的回調(diào)以及動(dòng)畫(huà)需要停止的位置。

在演示示例之前阁猜,我們來(lái)介紹一下finishAnimationAtPosition:丸逸。

  • -finishAnimationAtPosition::結(jié)束動(dòng)畫(huà)

該方法可以將處于 stopped 狀態(tài)的動(dòng)畫(huà)重置為非活躍狀態(tài)宇色,并執(zhí)行動(dòng)畫(huà)的完成塊喇澡。

此方法通常配合 -stopAnimation: 使用,并且該方法必須在動(dòng)畫(huà)器狀態(tài)為 stopped 狀態(tài)才可以诫尽,否則會(huì)出現(xiàn)錯(cuò)誤民效。該方法的 UIViewAnimatingPosition 參數(shù)有一下三種:

UIViewAnimatingPositionEnd //動(dòng)畫(huà)的終點(diǎn)位置
UIViewAnimatingPositionStart //動(dòng)畫(huà)的開(kāi)頭位置
UIViewAnimatingPositionCurrent //動(dòng)畫(huà)當(dāng)前位置

指定 UIViewAnimatingPositionCurrent 以使視圖屬性與其當(dāng)前值保持不變憔维。

示例:我們繼續(xù)之前的例子,這次我們配合 -finishAnimationAtPosition: 方法使用畏邢。

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:2.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
} completion:^(UIViewAnimatingPosition finalPosition) {
    // 動(dòng)畫(huà)的完成回調(diào)
    self.contentView.backgroundColor = UIColor.redColor;
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [animator stopAnimation:NO];
    // 動(dòng)畫(huà)器的狀態(tài)必須是stopped
    if (animator.state==UIViewAnimatingStateStopped) {
        [animator finishAnimationAtPosition:UIViewAnimatingPositionCurrent];
    }
});
withoutFinishing為NO的情況

我們發(fā)現(xiàn)业扒,動(dòng)畫(huà)運(yùn)行1秒后停止了,并且背景色被填充為紅色舒萎,這說(shuō)明-finishAnimationAtPosition:觸發(fā)完成塊凶赁,這一點(diǎn)和之前的例子是不同的。另外逆甜,我們看到視圖停下來(lái)之后就保持在了當(dāng)前位置,這是因?yàn)槲覀兘o的結(jié)束位置就是 Current致板。下圖演示了位置的不同參數(shù)的效果交煞。

start、current斟或、end三種不同位置

交互式動(dòng)畫(huà)

fractionComplete 屬性

UIViewPropertyAnimator 類(lèi)中有一個(gè)fractionComplete屬性素征,這個(gè)屬性表示當(dāng)前動(dòng)畫(huà)的完成的百分比,并且這個(gè)屬性不是只讀的屬性萝挤,這說(shuō)明我們可以精準(zhǔn)的控制動(dòng)畫(huà)的整個(gè)過(guò)程御毅。利用它,我們可以制作交互式動(dòng)畫(huà)怜珍。交互式動(dòng)畫(huà)的好處是:對(duì)于多個(gè)視圖端蛆、非常復(fù)雜的視圖變化加以控制變得簡(jiǎn)單。

示例:

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *blueView;
@property (weak, nonatomic) IBOutlet UIView *redView;
@property (weak, nonatomic) IBOutlet UISlider *slider;
@property (strong, nonatomic) UIViewPropertyAnimator* animator;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 初始化動(dòng)畫(huà)器
    
    self.animator = [[UIViewPropertyAnimator alloc] initWithDuration:2.0 curve:UIViewAnimationCurveLinear animations:^{
        // 紅色視圖
        
        CGRect fram = CGRectMake(self.slider.center.x - 50/2.0, self.slider.center.y - 100, 50, 50);
        self.redView.frame = fram;
        self.redView.transform = CGAffineTransformMakeRotation(M_PI);
        self.redView.backgroundColor = UIColor.blueColor;
        // 藍(lán)色視圖
        
        self.blueView.frame = fram;
        self.blueView.transform = self.redView.transform;
        self.blueView.backgroundColor = UIColor.redColor;
    }];
    [self.slider addTarget:self action:@selector(change:) forControlEvents:UIControlEventValueChanged];
}

-(void)change:(UISlider*)slider{
    CGFloat value = slider.value;
    // 更改動(dòng)畫(huà)完成度
    
    self.animator.fractionComplete = value;
}
控制兩個(gè)視圖之間的動(dòng)畫(huà)

需要注意的是酥泛,在使用fractionComplete之前今豆,最好調(diào)用-pauseAnimation暫停當(dāng)前動(dòng)畫(huà),此時(shí)動(dòng)畫(huà)處于活躍狀態(tài)柔袁,但非isRunning呆躲。

修改動(dòng)畫(huà)

正如前面簡(jiǎn)介中提到過(guò),UIViewPropertyAnimator 可以修改動(dòng)畫(huà)捶索,甚至是在動(dòng)畫(huà)處于運(yùn)行狀態(tài)插掂。我們可以添加多個(gè)動(dòng)畫(huà)塊、完成塊,設(shè)置是暫停掉正在執(zhí)行的動(dòng)畫(huà)辅甥,并且修改它的剩余時(shí)間酝润,這讓我們更加的精準(zhǔn)的控制視圖的動(dòng)畫(huà)行為。

  • -addAnimations::為視圖添加動(dòng)畫(huà)塊

我們之前在使用自定義時(shí)間速率對(duì)象初始化動(dòng)畫(huà)器時(shí)肆氓,曾經(jīng)使用到過(guò)該方法袍祖,此方法可以讓我們對(duì)視圖的動(dòng)畫(huà)追加多個(gè)動(dòng)畫(huà)塊。

示例:我們?yōu)檎谶\(yùn)動(dòng)的視圖添加漸變動(dòng)畫(huà)

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:1.0 delay:0 options:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
} completion:nil];
// 追加動(dòng)畫(huà)塊
[animator addAnimations:^{
    self.contentView.backgroundColor = UIColor.redColor;
}];
追加動(dòng)畫(huà)塊

我們追加的動(dòng)畫(huà)塊會(huì)和其他動(dòng)畫(huà)共享動(dòng)畫(huà)器剩余的時(shí)間谢揪。

示例:延遲追加動(dòng)畫(huà)

為了明顯的看出效果蕉陋,我們給予更長(zhǎng)的動(dòng)畫(huà)時(shí)間,并在運(yùn)行一段時(shí)間后拨扶,追加動(dòng)畫(huà)凳鬓。

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:4.0 delay:0 options:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
} completion:nil];
// 追加動(dòng)畫(huà)塊
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [animator addAnimations:^{
        self.contentView.backgroundColor = UIColor.redColor;
    }];
});
共享時(shí)間

我們看到2秒后追加的漸變動(dòng)畫(huà)在剩余的2秒內(nèi)完成了漸變效果。

當(dāng)然患民,蘋(píng)果已經(jīng)給出了類(lèi)似的方法缩举,無(wú)需我們主動(dòng)寫(xiě)延遲方法。就像下面的演示匹颤。

  • -addAnimations:delayFactor::延遲追加動(dòng)畫(huà)塊

參數(shù)delayFactor是指時(shí)間因子仅孩,即動(dòng)畫(huà)的進(jìn)度,取值區(qū)間為(0印蓖,1)辽慕。比如,0.5表示動(dòng)畫(huà)執(zhí)行一半的時(shí)候執(zhí)行赦肃。

示例:我們使用該方法完成之前的例子

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:4.0 delay:0 options:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
} completion:nil];
// 延遲追加動(dòng)畫(huà)塊
[animator addAnimations:^{
    self.contentView.backgroundColor = UIColor.redColor;
} delayFactor:0.5];
延遲加載動(dòng)畫(huà)
  • -addCompletion::追加完成塊

既然動(dòng)畫(huà)塊都可以追加修改溅蛉,那么完成塊也應(yīng)該相應(yīng)的有追加方法呀!

在初始化以動(dòng)畫(huà)器一節(jié)中他宛,我們發(fā)現(xiàn)大部分都是不帶有完成塊回調(diào)的船侧,蘋(píng)果似乎考慮到開(kāi)發(fā)過(guò)程中很少會(huì)關(guān)心動(dòng)畫(huà)的完成事件吧,因此為了方法的簡(jiǎn)潔性厅各,就讓其變成了可選特性镜撩,又或者這樣設(shè)計(jì)會(huì)讓動(dòng)畫(huà)變得更加的靈活,因?yàn)檫@樣讯检,動(dòng)畫(huà)的完成事件就無(wú)需緊跟在初始化方法上了琐鲁。

示例:我們?cè)趧?dòng)畫(huà)執(zhí)行完成時(shí)執(zhí)行一些事情

這里為了方便看到效果,我們就直接來(lái)改變視圖的顏色人灼。

UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0 curve:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}];
[animator startAnimation];
// 追加完成塊
[animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
    self.contentView.backgroundColor = UIColor.redColor;
}];
追加完成塊

在【控制動(dòng)畫(huà)】一節(jié)中围段,我們提到過(guò),我們可以調(diào)用-startAnimation:來(lái)恢復(fù)暫停后的動(dòng)畫(huà)投放,但是這樣做的話(huà)奈泪,動(dòng)畫(huà)的形式依舊是之前設(shè)置好的情況,它并不會(huì)發(fā)生變化。那么涝桅,如果想要暫定動(dòng)畫(huà)后拜姿,執(zhí)行其他時(shí)間速率的動(dòng)畫(huà)該怎么辦呢? UIViewPropertyAnimator 可以讓我們?nèi)我獾目刂苿?dòng)畫(huà)冯遂,必然會(huì)提供該類(lèi)方法蕊肥。

  • -continueAnimationWithTimingParameters:durationFactor::暫停后修改動(dòng)畫(huà)方式繼續(xù)執(zhí)行

該類(lèi)方法只會(huì)在調(diào)用-pauseAnimation方法之后起到作用,此時(shí)的動(dòng)畫(huà)狀態(tài)為蛤肌,活躍但非isRunning壁却。

參數(shù)durationFactor是時(shí)間因子,表示動(dòng)畫(huà)的進(jìn)度裸准。通痴苟可以取fractionComplete屬性。

示例:我們將勻速運(yùn)行中的視圖中途改為彈性運(yùn)動(dòng)

UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:2 curve:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}];
[animator startAnimation];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 暫停動(dòng)畫(huà)之后
    [animator pauseAnimation];
    // 暫停動(dòng)畫(huà)之后炒俱,修改動(dòng)畫(huà)時(shí)間速率后繼續(xù)動(dòng)畫(huà)
    UISpringTimingParameters* timing = [[UISpringTimingParameters alloc] initWithDampingRatio:0.2];
    [animator continueAnimationWithTimingParameters:timing durationFactor:animator.fractionComplete];
});
中途更改動(dòng)畫(huà)

上圖演示了中途更改的動(dòng)畫(huà)情況盐肃,其中,底下的視圖為參考視圖权悟,即未改變的勻速運(yùn)動(dòng)砸王。

以上就是快速入門(mén)使用的所有教程了,相信經(jīng)過(guò)一系列的介紹之后峦阁,你能夠快速的使用新的動(dòng)畫(huà)方式了处硬。

接下來(lái)的進(jìn)階篇,會(huì)講解一些 UIViewPropertyAnimator 的一些細(xì)節(jié)部分拇派。

進(jìn)階篇

動(dòng)畫(huà)協(xié)議

其實(shí)要介紹 UIViewPropertyAnimator 類(lèi)前,應(yīng)該先介紹其遵循的動(dòng)畫(huà)協(xié)議--UIViewAnimating 和 UIViewImplicitlyAnimating 凿跳。前者是后者的父類(lèi)件豌,我們先來(lái)解釋 UIViewAnimating 協(xié)議。該協(xié)議定義了操作動(dòng)畫(huà)的基本方法控嗜,包括啟動(dòng)茧彤、停止、暫停動(dòng)畫(huà)的能力疆栏。另外還有幾個(gè)屬性用于反映動(dòng)畫(huà)的當(dāng)前狀態(tài)信息曾掂。

UIViewPropertyAnimator 遵循并實(shí)現(xiàn)了 UIViewAnimating 協(xié)議的所有方法,因此我們可以用 UIViewPropertyAnimator 來(lái)實(shí)現(xiàn)動(dòng)畫(huà)的控制壁顶。如果你想在自定義類(lèi)中也遵循此協(xié)議珠洗,最好實(shí)現(xiàn)所有的協(xié)議方法和屬性。

動(dòng)畫(huà)的狀態(tài)

UIViewPropertyAnimator 有著一套完整的狀態(tài)機(jī)制若专。在動(dòng)畫(huà)器處理一組動(dòng)畫(huà)時(shí)许蓖,都會(huì)伴隨著這一系列的動(dòng)畫(huà)狀態(tài)。這些狀態(tài)定義了動(dòng)畫(huà)器的行為,包括它是如何處理變化的膊爪。如果你在實(shí)現(xiàn)自定義動(dòng)畫(huà)器自阱,必須遵循這些狀態(tài)的轉(zhuǎn)換并準(zhǔn)確的更新?tīng)顟B(tài)屬性。下圖顯示了發(fā)生的狀態(tài)和狀態(tài)轉(zhuǎn)換關(guān)系米酬。

狀態(tài)轉(zhuǎn)換關(guān)系

Inactive非活躍狀態(tài)是動(dòng)畫(huà)器的初始狀態(tài)沛豌。每個(gè)新創(chuàng)建的動(dòng)畫(huà)器都會(huì)處于非活躍狀態(tài)下啟動(dòng)。相對(duì)的赃额,動(dòng)畫(huà)正常完成后會(huì)返回到非活躍狀態(tài)加派。

當(dāng)我們調(diào)用-startAnimation-pauseAnimation方法時(shí),此時(shí)動(dòng)畫(huà)器會(huì)變?yōu)?code>Active活躍狀態(tài)爬早。此狀態(tài)下的動(dòng)畫(huà)器正在運(yùn)行或暫停狀態(tài)哼丈。如果是動(dòng)畫(huà)被暫停,我們此時(shí)還可以修改動(dòng)畫(huà)時(shí)間速率曲線(xiàn)筛严,讓后讓其繼續(xù)運(yùn)行到預(yù)期結(jié)束醉旦,結(jié)束后的動(dòng)畫(huà)器狀態(tài)依舊是Inactive非活躍狀態(tài),等待我們使用一組新的動(dòng)畫(huà)重新配置它桨啃,以便開(kāi)始新的動(dòng)畫(huà)车胡。

當(dāng)我們開(kāi)啟動(dòng)畫(huà)之后,調(diào)用-stopAnimation:方法會(huì)停止正在運(yùn)行的動(dòng)畫(huà)照瘾,此時(shí)視圖會(huì)被保留在停止的那一刻的值匈棘。此方法的參數(shù)值決定了當(dāng)前的動(dòng)畫(huà)信息是否被擦除。如果參數(shù) withoutFinishing 是 YES析命,則表示擦除當(dāng)前動(dòng)畫(huà)的信息主卫,動(dòng)畫(huà)器進(jìn)入Inactive狀態(tài),需要注意鹃愤,這種情況下簇搅,動(dòng)畫(huà)器是不會(huì)執(zhí)行完成塊的,換句話(huà)說(shuō)你無(wú)法在完成塊中得到動(dòng)畫(huà)結(jié)束信息软吐,此時(shí)如果你需要知道動(dòng)畫(huà)結(jié)束的事件瘩将,你可以使用 KVO 的方法監(jiān)聽(tīng)屬性isRunning獲得。如果參數(shù) withoutFinishing 是 NO凹耙,則表示保留當(dāng)前動(dòng)畫(huà)的信息姿现,動(dòng)畫(huà)器進(jìn)入Stopped狀態(tài),此時(shí)我們可以去完成其他的操作肖抱,如執(zhí)行其他動(dòng)畫(huà)备典。然后我們調(diào)用方法-finishAnimationAtPosition:以結(jié)束此次動(dòng)畫(huà),動(dòng)畫(huà)器順理成章的進(jìn)入到Inactive狀態(tài)意述。注意熊经,這情情況下泽艘,動(dòng)畫(huà)器可以順利的執(zhí)行完成塊內(nèi)容。

動(dòng)畫(huà)狀態(tài)的幾個(gè)枚舉:

typedef NS_ENUM(NSInteger, UIViewAnimatingState)
{
    UIViewAnimatingStateInactive, // The animation is not executing.
    UIViewAnimatingStateActive,   // The animation is executing.
    UIViewAnimatingStateStopped,  // The animation has been stopped and has not transitioned to inactive.
} NS_ENUM_AVAILABLE_IOS(10_0) ;

協(xié)議內(nèi)容

方法

  • -startAnimation 開(kāi)始動(dòng)畫(huà)

不可以在動(dòng)畫(huà)器調(diào)用方法-stopAnimation:直接結(jié)束動(dòng)畫(huà)后再次調(diào)用-startAnimation镐依,換句話(huà)說(shuō)匹涮,使用過(guò)程中,出現(xiàn)下面情況會(huì)出錯(cuò):

錯(cuò)誤
錯(cuò)誤

我們發(fā)現(xiàn)槐壳,在我們-stopAnimation:指定參數(shù)為 YES時(shí)然低,動(dòng)畫(huà)器狀態(tài)由活躍狀態(tài)Active轉(zhuǎn)變?yōu)榉腔钴S狀態(tài)Inactive,此時(shí)再次調(diào)用-startAnimation時(shí)务唐,系統(tǒng)拋出了異常雳攘。

而我們指定參數(shù)為 NO時(shí),

正常

此時(shí)動(dòng)畫(huà)器狀態(tài)為stopped枫笛,程序并未出錯(cuò)吨灭。

正常

這一點(diǎn)和官方文檔的說(shuō)明并不一致,目前還不是很清楚原因刑巧。

It is a programmer error to call this method while the state of the animator is set to UIViewAnimatingStateStopped.

??:11-29喧兄,以上結(jié)論基于10.3.2系統(tǒng),但是筆者使用11以上的系統(tǒng)發(fā)現(xiàn)啊楚,結(jié)論和上述相反吠冤,卻和官方文檔一致,即動(dòng)畫(huà)器狀態(tài)為stopped下恭理,不能使用-startAnimation拯辙。這一點(diǎn)讓我更加凌亂了,難道后面的系統(tǒng)修正了颜价?

  • -startAnimationAfterDelay: 延遲后開(kāi)始動(dòng)畫(huà)

上面的開(kāi)啟動(dòng)畫(huà)一樣的注意點(diǎn)同樣適用涯保。(請(qǐng)注意上面 11-29 的說(shuō)明)

另外經(jīng)測(cè)試發(fā)現(xiàn),-pauseAnimation之后調(diào)用-startAnimationAfterDelay:會(huì)發(fā)生程序錯(cuò)誤周伦。

  • -pauseAnimation 暫停動(dòng)畫(huà)

暫停動(dòng)畫(huà)后遭赂,可以使用-startAnimation方法重新恢復(fù)動(dòng)畫(huà),另外你也可以使用協(xié)議UIViewImplicitlyAnimating中的continueAnimationWithTimingParameters:durationFactor:恢復(fù)動(dòng)畫(huà)横辆。如果動(dòng)畫(huà)已經(jīng)暫停,則再次調(diào)用-pauseAnimation不會(huì)執(zhí)行任何操作茄猫。

經(jīng)測(cè)試發(fā)現(xiàn)如果動(dòng)畫(huà)器從未啟動(dòng)過(guò)狈蚤,直接調(diào)用-pauseAnimation方法,如果緊接著調(diào)用-startAnimation或者continueAnimationWithTimingParameters:durationFactor:是無(wú)法恢復(fù)動(dòng)畫(huà)的划纽,之間需要大于千分之一秒的時(shí)間脆侮,就像下面的情況:

無(wú)法恢復(fù)動(dòng)畫(huà)的情況:

[self.animator pauseAnimation];
[self.animator startAnimation];
//[self.animator continueAnimationWithTimingParameters:[[UICubicTimingParameters alloc] initWithAnimationCurve:UIViewAnimationCurveLinear] durationFactor:0.5];

如果之前調(diào)用過(guò)開(kāi)啟動(dòng)畫(huà),則可以恢復(fù)動(dòng)畫(huà)

[self.animator startAnimation];
...
[self.animator pauseAnimation];
[self.animator startAnimation];
//[self.animator continueAnimationWithTimingParameters:[[UICubicTimingParameters alloc] initWithAnimationCurve:UIViewAnimationCurveLinear] durationFactor:0.5];

又或者添加延遲

// 從未開(kāi)啟過(guò)勇劣,暫停動(dòng)畫(huà)
[self.animator pauseAnimation];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.002 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self.animator startAnimation];
//    [self.animator continueAnimationWithTimingParameters:[[UICubicTimingParameters alloc] initWithAnimationCurve:UIViewAnimationCurveLinear] durationFactor:0.5];
});

至于為什么會(huì)時(shí)這種情況靖避,官方文檔并未指出潭枣,或許只有蘋(píng)果自己清楚吧。

另外幻捏,官方文檔指出動(dòng)畫(huà)器為stopped狀態(tài)時(shí)盆犁,調(diào)用-pauseAnimation會(huì)出現(xiàn)程序錯(cuò)誤,但并沒(méi)有篡九。

??:11-29谐岁,以上結(jié)論基于10.3.2系統(tǒng),使用11以上的系統(tǒng)發(fā)現(xiàn)并不會(huì)出現(xiàn)【無(wú)法啟動(dòng)暫停動(dòng)畫(huà)】的情況榛臼,并且伊佃,動(dòng)畫(huà)器為stopped狀態(tài)時(shí),調(diào)用-pauseAnimation時(shí)沛善,確實(shí)出現(xiàn)程序錯(cuò)誤航揉。

  • -stopAnimation: 停止動(dòng)畫(huà)

需要注意的是,不可以在動(dòng)畫(huà)器狀態(tài)由Active轉(zhuǎn)為為stopped的時(shí)候再調(diào)用該方法金刁。下面的使用會(huì)發(fā)生程序錯(cuò)誤:

錯(cuò)誤使用

上圖中的調(diào)用-pauseAnimation將動(dòng)畫(huà)器轉(zhuǎn)為Active也會(huì)出現(xiàn)錯(cuò)誤帅涂。

這一點(diǎn),官方文檔卻并未提及胀葱。why漠秋?

  • -finishAnimationAtPosition: 結(jié)束動(dòng)畫(huà)

該方法通常會(huì)和上面的停止方法相結(jié)合,用來(lái)結(jié)束當(dāng)前停止下來(lái)(狀態(tài)為stopped)動(dòng)畫(huà)順利回到Inactive狀態(tài)抵屿。經(jīng)測(cè)試庆锦,該方法只認(rèn)stopped狀態(tài),其他兩個(gè)狀態(tài)都會(huì)發(fā)生錯(cuò)誤轧葛。

屬性

  • fractionComplete動(dòng)畫(huà)執(zhí)行的進(jìn)度

描述了當(dāng)前動(dòng)畫(huà)的進(jìn)度搂抒,可被更改,當(dāng)動(dòng)畫(huà)處于停止時(shí)尿扯,可配合手勢(shì)等實(shí)現(xiàn)交互式動(dòng)畫(huà)求晶。

  • reversed是否可以反轉(zhuǎn)動(dòng)畫(huà)

關(guān)于反轉(zhuǎn)動(dòng)畫(huà),目前還未知如果實(shí)現(xiàn)反轉(zhuǎn)動(dòng)畫(huà)衷笋。

  • state動(dòng)畫(huà)器的狀態(tài)

  • running動(dòng)畫(huà)的運(yùn)行狀態(tài)芳杏,支持KVO

修改動(dòng)畫(huà)協(xié)議

UIViewImplicitlyAnimating 繼承自 UIViewAnimating 協(xié)議,在后者協(xié)議的基礎(chǔ)上又添加了一些額外的修改動(dòng)畫(huà)的方法辟宗。而我們使用的 UIViewPropertyAnimator 動(dòng)畫(huà)器就遵循了這個(gè)相對(duì)完善的協(xié)議爵赵,并實(shí)現(xiàn)了所有的方法。

方法

  • -addAnimations: 添加動(dòng)畫(huà)塊

使用此方法可以將新的動(dòng)畫(huà)塊添加到自定義動(dòng)畫(huà)對(duì)象泊脐。新的動(dòng)畫(huà)會(huì)與先前的動(dòng)畫(huà)一起運(yùn)行空幻,并從當(dāng)前時(shí)間開(kāi)始并與任何原始動(dòng)畫(huà)同時(shí)結(jié)束。

  • -addAnimations:delayFactor:添加延遲動(dòng)畫(huà)塊

同上容客,不過(guò)會(huì)從指定的延遲開(kāi)始并與任何原始動(dòng)畫(huà)同時(shí)結(jié)束秕铛。

參數(shù) delayFactor:用于延遲動(dòng)畫(huà)開(kāi)始的時(shí)間因子约郁。該值必須介于0.0和1.0之間。將此值乘以動(dòng)畫(huà)剩余持續(xù)時(shí)間但两,作為實(shí)際延遲鬓梅。例如,如果值0.5镜遣、動(dòng)畫(huà)器的持續(xù)時(shí)間為2.0己肮,則延遲一秒執(zhí)行動(dòng)畫(huà)。

  • -addCompletion:添加動(dòng)畫(huà)完成塊

回調(diào)動(dòng)畫(huà)完成的事件悲关,你可以在該 block 中完成其他操作谎僻。

參數(shù) withoutFinishing 有三種,表示最后動(dòng)畫(huà)結(jié)束的位置寓辱。

typedef NS_ENUM(NSInteger, UIViewAnimatingPosition) {
    UIViewAnimatingPositionEnd,
    UIViewAnimatingPositionStart,
    UIViewAnimatingPositionCurrent,
} NS_ENUM_AVAILABLE_IOS(10_0);

如果動(dòng)畫(huà)正常完成結(jié)束艘绍,位置參數(shù)為UIViewAnimatingPositionEnd,即最終的期望位置秫筏;

如果動(dòng)畫(huà)執(zhí)行過(guò)程中诱鞠,調(diào)用了-stopAnimation:,并且制定的參數(shù)為 YES这敬,動(dòng)畫(huà)器則不會(huì)調(diào)用完成塊航夺;

如果動(dòng)畫(huà)執(zhí)行過(guò)程中,調(diào)用了-stopAnimation:崔涂,并且制定的參數(shù)為 NO阳掐,此時(shí)需要調(diào)用finishAnimationAtPosition:配置結(jié)束動(dòng)畫(huà),此時(shí)完成塊中的位置參數(shù)由方法finishAnimationAtPosition:決定冷蚂。

  • -continueAnimationWithTimingParameters:durationFactor:調(diào)整暫停的動(dòng)畫(huà)的時(shí)間速率曲線(xiàn)和持續(xù)時(shí)間

參數(shù) parameters 是指時(shí)間速率曲線(xiàn)缭保,系統(tǒng)提供了兩種,兼容了 UIKit 內(nèi)置的四種時(shí)間速率曲線(xiàn)蝙茶、三次貝塞爾曲線(xiàn)艺骂、彈簧式的彈性動(dòng)畫(huà)。

UICubicTimingParameters
UISpringTimingParameters

參數(shù) durationFactor 是指動(dòng)畫(huà)原始持續(xù)時(shí)間的因子隆夯,取值為(0钳恕,1),將此值乘以動(dòng)畫(huà)的原始持續(xù)時(shí)間蹄衷,作為新的持續(xù)時(shí)間忧额。

UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:2 curve:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}];
[animator startAnimation];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [animator pauseAnimation];
    [animator continueAnimationWithTimingParameters:[[UICubicTimingParameters alloc] initWithAnimationCurve:UIViewAnimationCurveLinear] durationFactor:animator.fractionComplete];
});
修改動(dòng)畫(huà)持續(xù)時(shí)間

如果我們將 durationFactor 傳遞為當(dāng)前動(dòng)畫(huà)器的進(jìn)度值 fractionComplete ,你會(huì)發(fā)現(xiàn)執(zhí)行的動(dòng)畫(huà)并沒(méi)有什么變化宦芦,這是因?yàn)?fractionComplete 的值乘以原始持續(xù)時(shí)間就等于動(dòng)畫(huà)剩余的時(shí)間。

但是我們將值放大轴脐,比 fractionComplete 的值要大调卑,那么動(dòng)畫(huà)的剩余時(shí)間就會(huì)被拉長(zhǎng)抡砂,剩下的動(dòng)畫(huà)會(huì)在新的時(shí)間內(nèi)完成。

示例:我們將動(dòng)畫(huà)1秒后恬涧,將剩余的時(shí)間縮短為0.1倍

UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc] initWithDuration:2 curve:UIViewAnimationCurveLinear animations:^{
    self.contentView.center = CGPointMake(self.view.center.x+100, self.view.center.y);
}];
[animator startAnimation];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [animator pauseAnimation];
    [animator continueAnimationWithTimingParameters:[[UICubicTimingParameters alloc] initWithAnimationCurve:UIViewAnimationCurveLinear] durationFactor:0.1];
});
修改剩余動(dòng)畫(huà)的持續(xù)時(shí)間

當(dāng)前就像之前介紹的注益,你也可以改換當(dāng)前動(dòng)畫(huà)的時(shí)間速率曲線(xiàn),或者更換為彈性動(dòng)畫(huà)溯捆。

動(dòng)畫(huà)器

介紹完 UIViewPropertyAnimator 的兩種協(xié)議之后丑搔,我們來(lái)看下 UIViewPropertyAnimator 中的一些其小細(xì)節(jié)。

三次貝塞爾曲線(xiàn)

在構(gòu)建動(dòng)畫(huà)器的方法中提揍,有一個(gè)之前我們一提而過(guò)的方法:

-initWithDuration:controlPoint1:controlPoint2:animations:

這個(gè)方法可以讓我們自定義時(shí)間速率曲線(xiàn)啤月,采用的是三次貝塞爾曲線(xiàn),可能有些人并不清楚什么是三次貝塞爾曲線(xiàn)劳跃。三次貝塞爾曲線(xiàn)在繪制圖形時(shí)經(jīng)常出現(xiàn)谎仲,是有起點(diǎn)、終點(diǎn)以及兩個(gè)控制點(diǎn)產(chǎn)生的曲線(xiàn)刨仑。文字描述比較抽象郑诺,我們來(lái)看下圖:

三次貝塞爾曲線(xiàn)

該曲線(xiàn)的起點(diǎn)為(0,0)杉武,其終點(diǎn)為(1辙诞,1)。point1 和 point2 參數(shù)是定義生成的貝塞爾曲線(xiàn)形狀的控制點(diǎn)轻抱。其中飞涂,起點(diǎn)和控制點(diǎn)1的連線(xiàn)為曲線(xiàn)的切線(xiàn),終點(diǎn)和控制點(diǎn)2的連線(xiàn)也是曲線(xiàn)的切線(xiàn)十拣,控制點(diǎn)1和控制點(diǎn)2的連寫(xiě)也是曲線(xiàn)的切線(xiàn)封拧,這樣夭问,產(chǎn)生的曲線(xiàn)就是三次貝塞爾曲線(xiàn)缰趋。

該曲線(xiàn)的斜率定義了動(dòng)畫(huà)的不同時(shí)間速率捧杉,斜率越大秘血,速度越快,斜率越小速度越慢灰粮。上圖顯示了一個(gè)速率曲線(xiàn)仔涩,其中動(dòng)畫(huà)快速啟動(dòng)并快速完成粘舟,但在中間部分運(yùn)行得相對(duì)較慢佩研。

屬性

  • duration 只讀

動(dòng)畫(huà)的持續(xù)時(shí)間旬薯,只有在初始化動(dòng)畫(huà)器時(shí)指定該值适秩,稍后添加的動(dòng)畫(huà)僅在剩余的時(shí)間內(nèi)運(yùn)行秽荞。剩余時(shí)間由公式(1.0 - fractionComplete)* 持續(xù)時(shí)間確定蚂会。

  • delay 只讀

延遲動(dòng)畫(huà)時(shí)間,默認(rèn)值為0趁猴。如果要為此屬性設(shè)置值儡司,啟動(dòng)動(dòng)畫(huà)時(shí)則需要使用startAnimationAfterDelay:方法

  • timingParameters 只讀

描述速度的曲線(xiàn)捕犬,和duration一樣,只有在初始化 animator 指定該值碉碉」噶福可以使用此屬性稍后獲取這些參數(shù)蜡吧。

  • interruptible

動(dòng)畫(huà)中是否可被打斷占键。當(dāng)此屬性的值為 YES 時(shí)畔乙,我們可以使用-pauseAnimation-stopAnimation:方法來(lái)中斷動(dòng)畫(huà)并進(jìn)行更改。當(dāng)此屬性的值為 NO 時(shí)氮帐,在調(diào)用startAnimation方法后,動(dòng)畫(huà)將運(yùn)行至完成(并且不會(huì)中斷)楞艾。

如果使用動(dòng)畫(huà)器來(lái)實(shí)現(xiàn)可中斷的視圖控制器轉(zhuǎn)換硫眯,則此屬性必須為 YES择同。

  • userInteractionEnabled

動(dòng)畫(huà)中用戶(hù)是否可交互敲才。默認(rèn)值為 YES紧武。當(dāng)此屬性的值為 YES 時(shí)阻星,觸摸事件將正常傳遞給視圖妥箕,否則在動(dòng)畫(huà)持續(xù)時(shí)間內(nèi)會(huì)忽略用戶(hù)的觸摸事件畦幢。

  • manualHitTestingEnabled

動(dòng)畫(huà)中點(diǎn)擊測(cè)試的能力呛讲。默認(rèn)為 NO贝搁。

  • scrubsLinearly

暫停的動(dòng)畫(huà)是否使用線(xiàn)性擦除或者使用指定的時(shí)間速率曲線(xiàn)雷逆。iOS11之后可用。

  • pausesOnCompletion

動(dòng)畫(huà)完成后是否保持活動(dòng)狀態(tài)往产。默認(rèn)值為 NO仿村。iOS11之后可用蔼囊。

當(dāng)此屬性的值為 YES 時(shí)畏鼓,動(dòng)畫(huà)器完成后動(dòng)畫(huà)后將保持Active狀態(tài)云矫,并且不會(huì)執(zhí)行完成塊让禀。此時(shí)我們可以撤消動(dòng)畫(huà)巡揍。當(dāng)此屬性的值為 NO 時(shí)吼肥,動(dòng)畫(huà)完成后缀皱,動(dòng)畫(huà)器執(zhí)行完成塊,自動(dòng)轉(zhuǎn)換為Inactive狀態(tài)表箭,從而結(jié)束動(dòng)畫(huà)免钻。

注:由于 YES 的情況下极舔,動(dòng)畫(huà)器并且不會(huì)執(zhí)行完成塊拆魏,因此如果你想要知道動(dòng)畫(huà)的結(jié)束事件渤刃,你需要監(jiān)聽(tīng)動(dòng)畫(huà)器的running屬性卖子。

補(bǔ)充

  • 設(shè)置同一可動(dòng)畫(huà)屬性

-addAnimations:方法可以讓我們添加多個(gè)屬性動(dòng)畫(huà)塊洋闽,那么喊递,如果兩個(gè)或多個(gè)動(dòng)畫(huà)需要同時(shí)改變相同的屬性會(huì)發(fā)生什么呢骚勘?蘋(píng)果采用的是“后者優(yōu)先”原則俏讹。即:后添加的動(dòng)畫(huà)效果會(huì)覆蓋之前的動(dòng)畫(huà)效果泽疆。但有趣的是殉疼,這將導(dǎo)致卡頓瓢娜,因?yàn)樾枰M合新舊動(dòng)畫(huà)眠砾,在舊動(dòng)畫(huà)淡出的同時(shí)會(huì)隱約看見(jiàn)新動(dòng)畫(huà)褒颈。

示例:

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:1.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.contentView.transform = CGAffineTransformMakeScale(1.5, 1.5);
[animator addAnimations:^{
    self.contentView.transform = CGAffineTransformMakeScale(0.5, 0.5);
}];
設(shè)置同一動(dòng)畫(huà)屬性

我們發(fā)現(xiàn)谷丸,后添加的縮小為0.5的動(dòng)畫(huà)效果覆蓋了之前的放大為1.5的動(dòng)畫(huà)效果淤井。但這似乎看不出所為卡頓的效果币狠,那我們來(lái)看下填充背景色會(huì)發(fā)生什么漩绵。

UIViewPropertyAnimator* animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:1.0 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.contentView.backgroundColor = UIColor.redColor;
} completion:nil];
[animator addAnimations:^{
    self.contentView.backgroundColor = UIColor.yellowColor;
}];
設(shè)置同一動(dòng)畫(huà)屬性

該示例中宝踪,視圖的最初顏色為藍(lán)色瘩燥,在第一個(gè)動(dòng)畫(huà)塊中厉膀,我們將其設(shè)置為紅色服鹅,后又設(shè)置為黃色企软。在該動(dòng)畫(huà)運(yùn)行過(guò)程中仗哨,我們發(fā)現(xiàn)藻治,視圖立刻被設(shè)置為紅色桩卵,然后由紅色漸變?yōu)辄S色雏节。因此钩乍,在多個(gè)動(dòng)畫(huà)塊中設(shè)置同一個(gè)動(dòng)畫(huà)屬性并不可控寥粹,我們應(yīng)該盡可能的避免這種情況的出現(xiàn)涝涤。


總結(jié)

UIViewPropertyAnimator 類(lèi)讓我們能夠精準(zhǔn)的控制視圖動(dòng)畫(huà)的每個(gè)細(xì)節(jié)阔拳。我們可以使用該類(lèi)完成各種動(dòng)畫(huà)的設(shè)置糊肠,中途修改動(dòng)畫(huà)货裹,甚至可以便捷的完成交互性的動(dòng)畫(huà)弧圆,這徹底改變了我們?cè)O(shè)置視圖動(dòng)畫(huà)的習(xí)慣墓阀,這些改變令人驚喜萬(wàn)分斯撮。

在進(jìn)階篇中勿锅,我們發(fā)現(xiàn)了很多異常的情況溢十,并且在不同的系統(tǒng)上有著不同的表現(xiàn)张弛,甚至是完全相反的情況吞鸭,這一點(diǎn)讓人非常的疑惑刻剥,筆者猜想可能是蘋(píng)果在 iOS11 系統(tǒng)之后改變了 UIViewPropertyAnimator 的一些實(shí)現(xiàn)細(xì)節(jié)部分造虏,導(dǎo)致了前后不一致的情況陶珠,但是在這種情況下背率,想要使用該類(lèi)需要異常謹(jǐn)慎寝姿。

但是饵筑,不能夠因噎廢食根资,如果我們開(kāi)發(fā)過(guò)程中能夠注意到這些異常的情況玄帕,避免這些異常操作裤纹,UIViewPropertyAnimator 不失為一個(gè)較為良好的動(dòng)畫(huà)類(lèi)鹰椒。

根據(jù)之前的問(wèn)題,有幾點(diǎn)建議:

  • 創(chuàng)建完動(dòng)畫(huà)器之后奸汇,請(qǐng)使用-startAnimation-startAnimationAfterDelay:方法開(kāi)啟動(dòng)畫(huà)茫蛹,或者直接使用+ runningPropertyAnimatorWithDuration:delay:options:animations:completion:

  • stopped情況下婴洼,請(qǐng)配合-finishAnimationAtPosition:方法結(jié)束后續(xù)動(dòng)畫(huà)柬采,而非其他方法

  • 在暫停動(dòng)畫(huà)的情況下粉捻,請(qǐng)使用-startAnimation-continueAnimationWithTimingParameters:durationFactor:方法恢復(fù)動(dòng)畫(huà)祟霍,可能的話(huà)沸呐,請(qǐng)保證動(dòng)畫(huà)是由運(yùn)行中暫停的崭添,或者延遲大于千分之秒的時(shí)間恢復(fù)動(dòng)畫(huà)


相關(guān)閱讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市屁置,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帅容,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扰魂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蒋畜,警方通過(guò)查閱死者的電腦和手機(jī)姻成,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)均牢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)徘跪,“玉大人垮庐,你說(shuō)我怎么就攤上這事〗馇。” “怎么了护盈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)胸竞。 經(jīng)常有香客問(wèn)我卫枝,道長(zhǎng)校赤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任浑测,我火速辦了婚禮怎顾,結(jié)果婚禮上槐雾,老公的妹妹穿的比我還像新娘募强。我一直安慰自己崇摄,他們只是感情好擎值,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著逐抑,像睡著了一般鸠儿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上厕氨,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音命斧,去河邊找鬼田晚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛国葬,可吹牛的內(nèi)容都是我干的贤徒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼汇四,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼接奈!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起通孽,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤序宦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后利虫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體挨厚,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡堡僻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年糠惫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钉疫。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡硼讽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牲阁,到底是詐尸還是另有隱情固阁,我是刑警寧澤骑疆,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布蹋笼,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏刀崖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一潮梯、第九天 我趴在偏房一處隱蔽的房頂上張望驹沿。 院中可真熱鬧,春花似錦况褪、人聲如沸撕贞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捏膨。三九已至,卻和暖如春食侮,著一層夾襖步出監(jiān)牢的瞬間号涯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工锯七, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诚隙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓起胰,卻偏偏與公主長(zhǎng)得像久又,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子效五,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355