沒有時(shí)間延遲的動(dòng)畫
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.8f animations:^{
//這里對(duì)視圖的屬性進(jìn)行修改
weakSelf.imageView1.center = center1;
} completion:^(BOOL finished) {
}];
可以設(shè)置時(shí)間延遲的動(dòng)畫
[UIView animateWithDuration:0.8 delay:0.2 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse animations:^{
//這里對(duì)視圖的屬性進(jìn)行修改
weakSelf.imageView2.center = center2;
} completion:^(BOOL finished) {
}];
Note:需要注意的是options參數(shù)的設(shè)置,會(huì)有不同的效果
類似彈簧效果的動(dòng)畫
[UIView animateWithDuration:0.8 delay:0.5 usingSpringWithDamping:0.3f initialSpringVelocity:0.0f options:0 animations:^{
//這里對(duì)視圖的屬性進(jìn)行修改
weakSelf.imageView2.center = center2;
} completion:^(BOOL finished) {
}];
對(duì)函數(shù)animateWithDuration: delay:usingSpringWithDamping: initialSpringVelocity: options: animations: completion:
的解釋:
- usingSpringWithDamping: 取值范圍在0.0~1.0, 取值越小,震蕩幅度越大
- initialSpringVelocity:確定了在動(dòng)畫結(jié)束之前運(yùn)動(dòng)的速度。一般情況下都是設(shè)置為0。設(shè)值舉個(gè)例子來(lái)說(shuō),如果想要移動(dòng)的距離為200pt,移動(dòng)速度為100pt/s,就需要設(shè)置為0.5。
設(shè)置position會(huì)有彈簧效果,設(shè)置視圖的bounds或transform同樣也會(huì)有彈簧效果的。
__weak typeof(self) weakSelf = self;
CGRect bounds = self.button.bounds;
bounds.size.width += 100;
// CGAffineTransform transform = CGAffineTransformMakeScale(1.3f, 1.0f);
[UIView animateWithDuration:2.0f delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:0 options:0 animations:^{
weakSelf.button.bounds = bounds;
// weakSelf.button.transform = transform;
// weakSelf.button.backgroundColor = [UIColor redColor];
} completion:^(BOOL finished) {
// weakSelf.button.transform = CGAffineTransformIdentity;
}];
以上方式可以在改變視圖的屬性時(shí)產(chǎn)生動(dòng)畫,如果視圖添加或者移除的時(shí)候想要添加動(dòng)畫,就要用到下面的方式了
Transitions
Transitions是在應(yīng)用到視圖之前預(yù)先定義好的。在動(dòng)畫開始知道結(jié)束,這些預(yù)先定義的動(dòng)畫都是不可改變和停止的。使用該方式動(dòng)畫之前需要有一個(gè)容器視圖,所有添加到該容器中子視圖出現(xiàn)時(shí)動(dòng)畫會(huì)執(zhí)行。
add/remove一個(gè)視圖
利用方法transitionWithView: duration: options: animations: completion:
來(lái)實(shí)現(xiàn)。解釋:
- transitionWithView:可以理解為所要添加視圖的父視圖
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong) UIButton *button;//觸發(fā)事件
@property(nonatomic,strong) UIView *containerView;//視圖容器
@property(nonatomic,strong) UIImageView *addImageView;//添加的視圖
@property(nonatomic,assign) BOOL show;//記錄是否已經(jīng)添加了視圖,默認(rèn)為NO
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view addSubview:self.containerView];
[self.view addSubview:self.button];
}
#pragma mark - Action
//按鈕事件
- (void)btnClick:(id)sender
{
self.addImageView.center = self.view.center;
__weak typeof(self) weakSelf = self;
[UIView transitionWithView:self.containerView duration:0.8 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionTransitionFlipFromBottom animations:^{
if (_show) {
//已經(jīng)存在了,就移除
[weakSelf.addImageView removeFromSuperview];
}
else{
//不存在,就添加
[weakSelf.containerView addSubview:weakSelf.addImageView];
}
_show = !_show;
} completion:^(BOOL finished) {
}];
}
#pragma mark - Getter
//按鈕
- (UIButton *)button
{
if (!_button) {
_button = [UIButton buttonWithType:UIButtonTypeCustom];
_button.bounds = CGRectMake(0, 0, 100, 30);
_button.center = CGPointMake(CGRectGetMidX(self.view.frame), 100);
[_button setTitle:@"點(diǎn)擊我" forState:UIControlStateNormal];
_button.backgroundColor = [UIColor redColor];
[_button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
//容器視圖
- (UIView *)containerView
{
if (!_containerView) {
_containerView = [[UIView alloc]initWithFrame:self.view.bounds];
}
return _containerView;
}
//所添加的視圖
- (UIImageView *)addImageView
{
if (!_addImageView) {
_addImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"banner"]];
_addImageView.bounds = CGRectMake(0, 0, 283, 49);
_addImageView.contentMode = UIViewContentModeScaleAspectFill;
}
return _addImageView;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Hide/Show 一個(gè)視圖
同樣也是利用方法transitionWithView: duration: options: animations: completion:
來(lái)實(shí)現(xiàn)。只不過(guò)是通過(guò)修改該視圖的hidden屬性來(lái)實(shí)現(xiàn)。
- transitionWithView:所要操作的視圖
嘗試不同options參數(shù),會(huì)有不同的驚喜。
先看效果
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong) UIButton *button;//觸發(fā)事件
@property(nonatomic,strong) NSMutableArray *titlesArray;//存放Messages
@property(nonatomic,strong) UIImageView *addImageView;//添加的視圖
@property(nonatomic,strong) UILabel *titleLabel;//顯示Message的Label
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view addSubview:self.containerView];
[self.view addSubview:self.button];
[self.view addSubview:self.addImageView];
[self.addImageView addSubview:self.titleLabel];
self.addImageView.hidden = YES;
[self.titlesArray addObjectsFromArray:@[@"人生若只如初見",@"何事悲風(fēng)秋畫扇",@"等閑變卻故人心",@"卻道故人心易變"]];
}
#pragma mark - Action
/*!
* @author Yooeee
*
* @brief 按鈕事件
*
* @param sender 按鈕
*/
- (void)btnClick:(id)sender
{
self.addImageView.center = self.view.center;
[self showMessage:0];
}
#pragma mark - Private Methods
/*!
* @author Yooeee
*
* @brief 顯示視圖
*
* @param index 顯示第幾個(gè)文字
*/
- (void)showMessage:(NSInteger)index
{
NSAssert(index < self.titlesArray.count, @"數(shù)組越界了");
self.titleLabel.text = self.titlesArray[index];
__weak typeof(self) weakSelf = self;
[UIView transitionWithView:self.addImageView duration:0.8f options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionTransitionFlipFromBottom animations:^{
weakSelf.addImageView.hidden = NO;
} completion:^(BOOL finished) {
//動(dòng)畫結(jié)束之后,為方便看效果,延遲兩秒執(zhí)行移除動(dòng)畫
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//判定一下數(shù)組
if (index < weakSelf.titlesArray.count) {
//隱藏執(zhí)行下一個(gè)動(dòng)畫
[self hideMessage:index];
}
else{
//做些其他的操作
NSLog(@"執(zhí)行完了");
}
});
}];
}
/*!
* @author Yooeee
*
* @brief 隱藏視圖
*
* @param index 隱藏第幾個(gè)文字
*/
- (void)hideMessage:(NSInteger)index
{
__weak typeof(self) weakSelf = self;
[UIView transitionWithView:self.addImageView duration:0.8f options:0 animations:^{
CGPoint center = weakSelf.addImageView.center;
center.x += weakSelf.view.frame.size.width;
weakSelf.addImageView.center = center;
} completion:^(BOOL finished) {
weakSelf.addImageView.hidden = YES;
weakSelf.addImageView.center = weakSelf.view.center;
//判定一下數(shù)組
if (index < weakSelf.titlesArray.count - 1) {
[self showMessage:index+1];
}
else{
//從頭開始執(zhí)行
[self showMessage:0];
}
}];
}
#pragma mark - Getter
/*!
* @author Yooeee
*
* @brief 觸發(fā)事件開始
*
* @return button
*/
- (UIButton *)button
{
if (!_button) {
_button = [UIButton buttonWithType:UIButtonTypeCustom];
_button.bounds = CGRectMake(0, 0, 100, 30);
_button.center = CGPointMake(CGRectGetMidX(self.view.frame), 100);
[_button setTitle:@"點(diǎn)擊我" forState:UIControlStateNormal];
_button.backgroundColor = [UIColor redColor];
[_button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
/*!
* @author Yooeee
*
* @brief 文本信息
*/
- (NSMutableArray *)titlesArray
{
if (!_titlesArray) {
_titlesArray = [[NSMutableArray alloc]init];
}
return _titlesArray;
}
/*!
* @author Yooeee
*
* @brief 創(chuàng)建添加的視圖
*
* @return 視圖
*/
- (UIImageView *)addImageView
{
if (!_addImageView) {
_addImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"banner"]];
_addImageView.bounds = CGRectMake(0, 0, 283, 49);
_addImageView.contentMode = UIViewContentModeScaleAspectFill;
}
return _addImageView;
}
/*!
* @author Yooeee
*
* @brief 展現(xiàn)文本信息的Label
*
* @return label
*/
- (UILabel *)titleLabel
{
if (!_titleLabel) {
_titleLabel = [[UILabel alloc]initWithFrame:self.addImageView.bounds];
_titleLabel.textAlignment = NSTextAlignmentCenter;
}
return _titleLabel;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
視圖的替換
利用方法transitionFromView: toView: duration: options: completion:
來(lái)實(shí)現(xiàn),是將toView添加到fromView的superview上,并且將fromView 從他的superview上移除。解釋:
transitionFromView: 被替換的視圖
-
toView: 替換的視圖
[UIView transitionFromView:_fromImageView toView:_toImageView duration:0.8f options:UIViewAnimationOptionTransitionCurlDown completion:^(BOOL finished) { }];
需要注意的是執(zhí)行動(dòng)畫的時(shí)候,整個(gè)superview都會(huì)執(zhí)行該動(dòng)畫。
利用輔助視圖的方式來(lái)實(shí)現(xiàn)動(dòng)畫
注意這種方法,可以利用輔助視圖來(lái)實(shí)現(xiàn)我們所需要的效果。
效果:
代碼如下:
/*!
* @author Yooeee
*
* @brief 動(dòng)態(tài)的切換文字
*
* @param label 所要改變文字的Label
* @param text 改變的文字
*/
- (void)cube:(UILabel *)label text:(NSString *)text
{
//輔助視圖,用來(lái)實(shí)現(xiàn)效果
UILabel *aLabel = [[UILabel alloc]initWithFrame:label.frame];
aLabel.text = text;
aLabel.textAlignment = label.textAlignment;
aLabel.font = label.font;
CGFloat offset = label.frame.size.height/2.0f;
aLabel.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, 0.1), CGAffineTransformMakeTranslation(0.0, offset));
[label.superview addSubview:aLabel];
[UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
aLabel.transform = CGAffineTransformIdentity;
label.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(1.0, 0.1), CGAffineTransformMakeTranslation(0.0, -offset));
} completion:^(BOOL finished) {
label.text = text;
label.transform = CGAffineTransformIdentity;
[aLabel removeFromSuperview];
}];
}
漸隱效果
主要是修改option的參數(shù)取值
先看效果:
[UIView transitionWithView:_fadeImageView duration:1.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
_fadeImageView.image = [UIImage imageNamed:@"image2"];
} completion:^(BOOL finished) {
}];
Keyframe Animations的實(shí)現(xiàn)
有時(shí)候我們需要實(shí)現(xiàn)多個(gè)連續(xù)的動(dòng)畫,或許我們可以在 completion中來(lái)實(shí)現(xiàn)多個(gè)動(dòng)畫的連續(xù),但是我們卻可以有更好的選擇,那就是 Keyframe Animations(幀動(dòng)畫)。
這里我們需要用到方法animateKeyframesWithDuration: delay: options: animations: completion:
。
- animateKeyframesWithDuration:所有動(dòng)畫完成的總時(shí)間
- delay:延遲執(zhí)行時(shí)間
- options:一些設(shè)置,他是枚舉類型
UIViewKeyFrameAnimationOptions
,不是UIViewAnimationOptions
,這個(gè)一定要注意。 - animations:我們的動(dòng)畫就添加到這里面
- completion:這個(gè)動(dòng)畫執(zhí)行完成后會(huì)執(zhí)行這里
使用方法addKeyframeWithRelativeStartTime: relativeDuration: animations:
來(lái)添加各個(gè)時(shí)間段內(nèi)的動(dòng)畫。
- startTime 指相對(duì)于全部動(dòng)畫時(shí)間的開始時(shí)間。比如總時(shí)間為10s,設(shè)值為0.3,則此動(dòng)畫就是第3秒開始。取值都在0~1.0之間。
- duration 指相對(duì)于全部動(dòng)畫時(shí)間的持續(xù)時(shí)間。比如總時(shí)間為10秒,設(shè)置為0.4,則此動(dòng)畫所持續(xù)的時(shí)間就是4秒。取值都在0~1.0之間。
舉個(gè)例子:實(shí)現(xiàn)效果先看
實(shí)現(xiàn)代碼
- (void)planeDepart
{
CGPoint originCenter = _planeImageView.center;
[UIView animateKeyframesWithDuration:1.5 delay:2.0 options:0 animations:^{
//在這里添加動(dòng)畫
[UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.25 animations:^{
CGPoint center = self.planeImageView.center;
center.x += 80.0f;
center.y -=10.0f;
self.planeImageView.center = center;
}];
[UIView addKeyframeWithRelativeStartTime:0.1 relativeDuration:0.4 animations:^{
self.planeImageView.transform = CGAffineTransformMakeRotation(-M_PI_4/2);
}];
[UIView addKeyframeWithRelativeStartTime:0.25 relativeDuration:0.25 animations:^{
CGPoint center = self.planeImageView.center;
center.x += 100.0f;
center.y -= 50.0f;
self.planeImageView.center = center;
self.planeImageView.alpha = 0.0;
}];
[UIView addKeyframeWithRelativeStartTime:0.51 relativeDuration:0.01 animations:^{
self.planeImageView.transform = CGAffineTransformIdentity;
self.planeImageView.center = CGPointMake(0, originCenter.y);
}];
[UIView addKeyframeWithRelativeStartTime:0.55 relativeDuration:0.45 animations:^{
self.planeImageView.alpha = 1.0;
self.planeImageView.center = originCenter;
}];
} completion:^(BOOL finished) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//兩秒之后重復(fù)執(zhí)行動(dòng)畫
[self planeDepart];
});
}];
}
上個(gè)源代碼吧 Plane
說(shuō)明:
- 各個(gè)幀動(dòng)畫之間的時(shí)間點(diǎn)是可以重疊的。