Motion Design for iOS(译文4)

我们已经初步了解核心动画并且可以通过优秀的JNWSpringAnimation框架来模仿一些弹簧系统效果,现在该实际演练了!

复制一个iOS的Alert View 效果

复制一个熟悉的提示窗是一个很好地熟悉动画实现过程的方法。接下来让我们来创建属于自己的提示框吧。
下面是一个内置提示框的一个效果。

neizhi.png

之前的部分已经解释过,将动画效果分解为各个组成部分的重要性,只有将他们进行分解,才能更好地去实现它。但是,这并不是简单的说“提示框显示到屏幕上”,你必须要知道每一步或者每个时间点发生了什么。让我们开始分解这个动画效果吧。

  1. 屏幕开始的时候有一个渐入的半透明的遮盖
  2. 提示框从完全透明并且1.x尺寸变化到完全不透明并且是原始尺寸。
  3. 在消失的时候重新变回完全透明并且缩放比例变为小于原始比例。
  4. 移除黑色遮盖

在我们开始写代码之前,让我们来看一下我们所要完成的最终效果。

zuihzong.png

首先,我们应该创建一个白色背景的系统window,只要应用一启动,应用的代理文件就是运行这段代码。你可以把这段代码写在Alert View 1 Xcode项目中。

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // Construct the main window for this application
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // All additional code in this example will go right here

    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

现在,我们已经有了一个正好覆盖整个屏幕的View了,并且backgroundColor被设置为白色。如果我们现在运行这段代码,只会在模拟器或者是手机上(如果你连接了手机的话)加载一个空白的额View。接着,我们需要往window上添加一个遮盖,将透明度设置为完全透明,因为我们现在还不想显示它。

UIView *overlayView = [[UIView alloc] initWithFrame:self.window.bounds];
overlayView.backgroundColor = [UIColor blackColor];
overlayView.alpha = 0.0f;
[self.window addSubview:overlayView];

这个overlayView只是一个覆盖整个屏幕的一个普通的UIView对象而已。为了展示我们现在所实现的一些效果,我们暂时将遮盖设置为完全不透明,下面就是现在的成果喽。
【黑色遮盖】

我们接着刚才的代码开始继续我们的提示框,但本例为了简化操作,使用了图片image而不是纯代码构建的文本框和按钮。

CGFloat alertDimension = 250;
CGRect alertViewFrame = CGRectMake(
    self.window.bounds.size.width/2 - alertDimension/2,
    self.window.bounds.size.height/2 - alertDimension/2,
    alertDimension, alertDimension);
UIView *alertView = [[UIView alloc] initWithFrame:alertViewFrame];

首先,我们需要创建的UIView对象会展示在屏幕的中央。这样可以通过屏幕的宽度和高度除以2,然后减去提示框一半的宽度和高度来得到提示框的位置。相对来说,我更喜欢通过一次性的设置动画的最终位置,然后根据transform属性来修改不同位置的不同大小。

alertView.backgroundColor = [UIColor colorWithPatternImage:
    [UIImage imageNamed:@"alert_box"]];
alertView.alpha = 0.0f;
alertView.transform = CGAffineTransformMakeScale(1.2, 1.2);
alertView.layer.cornerRadius = 10;

上面这段代码里,我们总共做了4件事:

  1. 将提示框的背景色backgroundColor设置为图片。
  2. 将透明度alpha设置为0,这样就会知道我们将它完全显示出来的时候他才会出现
  3. 通过CGAffineTransformMakeScale()transform属性设置为大于原始尺寸的大小。
  4. 通过cornerRadius来给提示框设置圆角属性。

接下来我们需要给它设置一些细微的阴影效果。

alertView.layer.shadowColor = [UIColor blackColor].CGColor;
alertView.layer.shadowOffset = CGSizeMake(0, 5);
alertView.layer.shadowOpacity = 0.3f;
alertView.layer.shadowRadius = 10.0f;
[self.window addSubview:alertView];

如果将遮盖的透明度设置为完全不透明,并且移除缩放的话,现在我们得到的结果是这样的:

jt.png

是时候添加一些动画效果了。对于遮盖来说,我们希望从不可见的完全透明到半透明。我们希望给提示框添加两个动画效果:opacity属性从0.0 变到 1.0,并且缩放比例从>1.0x的比例变化到1.0x大小。这就是我们要模仿的iOS7的提示框效果。

我们先来处理这两个动画效果(遮盖和提示框View),因为透明opacity属性的变化并不需要弹簧动画效果,我们使用一个简单的block来实现:

// Fade in the grey overlay and alert view
[UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut
    animations:^{
    overlayView.alpha = 0.3f;
    alertView.alpha = 1.0f;
} completion:NULL];

我们在一个block中实现了遮盖和提示框的透明度的变化。因为我想让他们同时以同样的方式出现在用户面前,但是为什么不一起使他们发生变化呢?我将动画持续时间设置为0.3s,当给用户展示重要信息的时候,就像iOS7里的提示框那样,一个放松的效果会使用户觉得更重要。相比较一个快速的动画效果而言,一个缓慢的动画效果会使用户觉得这个信息更加的重要并且需要多加注意。

现在我们该对提示框的尺寸进行改变了,我想用弹簧效果给这个提示框的出现增加一些趣味,而不仅仅是上面的那种简单的block动画方式。在标准的iOS提示框中,苹果并没有使用震荡效果达到最终的值而是使用了一种缓慢衰减的方法达到最终的位置和效果。我们将通过设置dampingstiffness的属性值来达到类似的效果。

// Scale-animate in the alert view
JNWSpringAnimation *scale = [JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 14;
scale.stiffness = 14;
scale.mass = 1;
scale.fromValue = @(1.2);
scale.toValue = @(1.0);

[alertView.layer addAnimation:scale forKey:scale.keyPath];
alertView.transform = CGAffineTransformMakeScale(1.0, 1.0);

大家可以运行一下看看,还不错吧?接下来我们需要处理消失的时候的动画效果。

像我们之前说过的,我们想让一个提示框在出现的时候是以一种缓慢的方式出现的,但是在提示框消失的时候,我不知道大家是怎么样的,反正我特希望提示框快速消失,回到我之前被打断的地方。

// Fade out the grey overlay and alert view
[UIView animateWithDuration:.15 delay:0 options:UIViewAnimationOptionCurveEaseInOut
    animations:^{
    overlayView.alpha = 0.0f;
    alertView.alpha = 0.0f;
} completion:NULL];

既然我们回到了最初的动画,现在我们需要遮盖和提示框的透明度都设置为完全透明的状态。又因为我想这两个一起进行动画效果,我将它们放在同一个block中。值得注意的是,提示框的淡出动画持续时间要比淡入动画的持续时间缩短了一半。我们希望这个提示框能够轻快的淡出屏幕。

接下来我们需要在透明度变为完全透明的时候将提示框缩小为更小。

// Scale-animate out the alert view
JNWSpringAnimation *scaleOut = [JNWSpringAnimation
    animationWithKeyPath:@"transform.scale"];
scaleOut.damping = 11;
scaleOut.stiffness = 11;
scaleOut.mass = 1;
scaleOut.fromValue = @(1.0);
scaleOut.toValue = @(0.7);

[alertView.layer addAnimation:scaleOut forKey:scaleOut.keyPath];
alertView.transform = CGAffineTransformMakeScale(0.7, 0.7);

创建更加高级的提示框

既然我们已经复制了系统自带的提示框的效果,那么我们要不要开始做一些自定义的具有更好效果的提示框呢?我们可以开启一个新的Alert View 2Xcode 项目。

为了实现这个动画效果,UIView和之前的例子中的属性有着相似的地方,但是这次我们要同时更新transform属性的translationscale.

alertView.transform = CGAffineTransformMakeScale(.25, .25);
alertView.transform = CGAffineTransformTranslate(alertView.transform, 0, 600);

这样会让提示框的大小缩放为原来的0.25倍大小,而且同时下移到屏幕底部。你也可以这样来同时实现上面的效果:

CGAffineTransform viewTransform = CGAffineTransformConcat(
    CGAffineTransformMakeScale(.25, .25), CGAffineTransformMakeTranslation(0, 600));
alertView.transform = viewTransform;

现在UIView对象已经缩放为原来的0.25倍,并且移动到屏幕底部。我们可以在将提示框变为1.0的同时移动到开始的屏幕中央的位置。我们仍然可以遮盖以同样的状态淡出。

// Fade the overlay and alert view together
UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut
    animations:^{
    overlayView.alpha = 0.2f;
    alertView.alpha = 1.0f;
} completion:NULL];

// Animate the alert’s scale from .25 up to 1.0
JNWSpringAnimation *scale =
    [JNWSpringAnimation animationWithKeyPath:@"transform.scale"];
scale.damping = 12;
scale.stiffness = 12;
scale.mass = 1;
scale.fromValue = @(.25);
scale.toValue = @(1.0);

[alertView.layer addAnimation:scale forKey:scale.keyPath];
alertView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0);

// Animate the position from the starting Y position of 600 back up to 0
// which puts it back at the original position
JNWSpringAnimation *translate = [JNWSpringAnimation
    animationWithKeyPath:@"transform.translation.y"];
translate.damping = 15;
translate.stiffness = 15;
translate.mass = 1;
translate.fromValue = @(600);
translate.toValue = @(0);

[alertView.layer addAnimation:translate forKey:translate.keyPath];
alertView.transform = CGAffineTransformTranslate(alertView.transform, 0, 0);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容