JazzHands + AutoLayout 基本使用

在上一篇文章中,我们已经能用JazzHands做出一个完整的 Guide 动画了,但是这个动画还有一些不足.

  • 它是用 Frame 来布局的,在不同的机型上适配起来很麻烦

JazzHands 2.0已经解决了这个问题
用 AutoLayout 来布局,用 IFTTTConstraintConstantAnimation 和 IFTTTConstraintMultiplierAnimation来做动画
使用起来代码会复杂一些,但是对屏幕适配,屏幕旋转, iPad split-screen 支持的更好.

使用 IFTTTAnimatedPagingScrollViewController

IFTTTAnimatedPagingScrollViewController 内部Override 下面这2个方法,结合 AutoLayout 完成适配.

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration:

接下来我们使用AutoLayout 和 JazzHands做一个简单的 透明度渐变动画.

创建一个空 ViewController 继承 IFTTTAnimatedPagingScrollViewController
这是 JazzHands 提供给我们的方便结合使用 AutoLayout 制作动画的类,以后我们使用 AutoLayout 做动画直接继承这个类就可以了,它已经帮我们初始化好了 scrollView,contentView,Animator

在类扩展中只需添加我们动画的 View

@interface JazzHandsPageViewControllerDemo ()
@property (strong,nonatomic) UIView  *v;
@end

在 ViewDidLoad 中

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.v=[UIView new];
    self.v.backgroundColor=[UIColor redColor];
    [self.contentView addSubview:self.v]; //注意添加 view到 contentView 中
    self.scrollView.showsHorizontalScrollIndicator=YES;
    self.scrollView.backgroundColor=[UIColor whiteColor];
    
    
    self.edgesForExtendedLayout = UIRectEdgeNone; //ios7以后 NavigationBar 会遮住内容,加上这行保证内容显示在 navigationBar 下面,一般来说我们的 Guide 动画都是全屏的,不需要加这行
    [self.v mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.height.equalTo(@30); //固定 view 宽高为30
    }];
    
    [self keepView:self.v onPage:0]; //keepView 下面会说到
    
    IFTTTAlphaAnimation *alpha=[IFTTTAlphaAnimation animationWithView:self.v];
    [self.animator addAnimation:alpha];
    
    [alpha addKeyframeForTime:0 alpha:1];
    [alpha addKeyframeForTime:1 alpha:0]; //注意 time 是 1
}

运行一下,效果如图

JazzHands+AutoLayoutDemo.gif

上面的代码和我们前2篇文章使用 Frame 布局制作动画类似,但有3点不同.

  1. 将 View 添加到了 contentView中.
  2. Masonry 给 view 布局
  3. addKeyframeForTime:1 time 是1.

关于第一点 : 将 View 添加到了 contentView中.

引用一段 斯坦福大学公开课:iOS 7应用开发

图片较大 - scrollView.gif
图片较大 - scrollView.gif

gif 中手机屏幕是全屏的 scrollView, 后面的图片是 contentView, 我们将contentView 用scrollView.addsubView(contentView), 添加到 scrollView 中,再将其他所有需要展示的 View 添加到 contentView 中, scrollView 是为后面的 ContentView提供一个窗口
我们手指滑动屏幕, scrollView.contentOffset.x 改变,我们能看到的 contentView 的内容看起来跟着滚动变化了,但实际上 contentView 的位置是固定的.

我们在继承 IFTTTAnimatedPagingScrollViewControllercontentView,scrollView 已经被初始化好了,我们只需将需要展示的 view 添加到 self.contentView 中即可

关于第二点

既然我们使用 AutoLayout, 那么对 view 进行布局,设置动画,就都要使用 AutoLayout, 这里使用 Mansonry 开源库来设置约束.

关于第三点 : addKeyframeForTime:1 time 是1.

之前我们使用 Frame

//创建一个透明度动画
    IFTTTAlphaAnimation *alpha=[IFTTTAlphaAnimation animationWithView:self.v];
    //将所有动画添加到 animator 中
    [self.animator addAnimation:alpha];

    //添加2个帧,在 scrollView 从 0 滚动到 200 时, 淡出我们的 View
    [alpha addKeyframeForTime:0 alpha:1.0];
    [alpha addKeyframeForTime:200 alpha:0.0];
    
    
    //scrollView 代理
    -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
        [self.animator animate:scrollView.contentOffset.x];
    }
}

现在我们使用 AutoLayout 和 IFTTTAnimatedPagingScrollViewController

    IFTTTAlphaAnimation *alpha=[IFTTTAlphaAnimation animationWithView:self.v];
    [self.animator addAnimation:alpha];
    
    [alpha addKeyframeForTime:0 alpha:1]; 
    [alpha addKeyframeForTime:1 alpha:0];

IFTTTAnimatedPagingScrollViewController内部帮我们做了scrollView.contentOffset.xtime 的转换
具体实现类似 :

    time = self.scrollView.contentOffset.x / self.pageWidth;

它将 contentOffset.x转换为 页面宽度的百分比,

    [alpha addKeyframeForTime:0 alpha:1];
    [alpha addKeyframeForTime:1 alpha:0];

所以这段代码我们设置的动画是, scrollView 从第一页滚动到第二页, view 的透明度从1变化到0

[keepView:onPage:]方法

如果你细心的话,可以发现上面的例子中,我们并没有设置 x 轴的约束,但是红色方块的位置在 X 轴居中,
就是因为[self keepView:self.v onPage:0];,这行代码

我们写一个例子来看看这个方法及其重载方法的作用,

新建一个空白 ViewController, 继承自 IFTTTAnimatedPagingScrollViewController

类扩展中

@interface JazzHandsKeepViewDemo ()
@property (strong,nonatomic) UIImageView *ifttt;
@end

ViewDidLoad 中

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.ifttt=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"IFTTTPresents"]];
    self.scrollView.backgroundColor=[UIColor greenColor];
    self.scrollView.showsHorizontalScrollIndicator=YES;
    [self.contentView addSubview:self.ifttt];
    
    self.edgesForExtendedLayout = UIRectEdgeNone;
    
    [self keepView:self.ifttt onPage:0]; 
}

我们还需要 Override 一个方法,告诉父类我们需要的页数

-(NSUInteger)numberOfPages{
    return 4;
}

运行一下,效果如图

KeepViewDemo.gif

我们并没有给 ITFFF imageView设置任何的动画和约束,但是它在 X轴居中,
就是因为我们设置了[self keepView:self.ifttt onPage:0];,让 imageView 出现在第一页,

我们继续使用它的重载方法..

    [self keepView:self.ifttt onPages:@[@(0),@(1)]]; 

运行结果如下..

KeepViewDemo_2.gif

注意看下面的 scrollIndicator, 即使我滑动到第二页,它还是保持在屏幕中间的位置,

继续修改代码为

    [self keepView:self.ifttt onPages:@[@(0),@(1)] atTimes:@[@(0),@(1)]];

这个运行的结果和上面一样,其实我们调用 [self keepView:self.ifttt onPages:@[@(0),@(1)]];时,
内部会调用它的重载方法
[self keepView:self.ifttt onPages:@[@(0),@(1)] atTimes:@[@(0),@(1)]];,
所以这2个方法的效果是一样的

再次修改代码,最后一次了...

    [self keepView:self.ifttt onPages:@[@(0),@(1.5)] atTimes:@[@(0),@(1)]]; 

运行结果如下

KeepViewDemo_3.gif

这个运行结果看起来有点诡异,
先来解释这个方法,

[self keepView:self.ifttt onPages:@[@(0),@(1)] atTimes:@[@(0),@(1)]]; 

调用这个方法起到的效果是, ImageView 会保持在第一页和第二页的中间,
当我们调用这个方法时,内部会给 imageView 和 contentView 添加一个 X 轴的约束,让 imageView 保持在页面中间,
onPages:@[@(0),@(1)] 就代表保持在第一二页的中间, atTimes:@[@(0),@(1)] 代表2个时间点,

它内部的实现是在 scrollView 滚动时,将 scrollView.contentOffset.x 累加给 imageView 和 contentView 的约束的 constant 上,也就是 scrollView 滚动多少, imageView 也滚动多少,所以产生的效果就是 imageView 一直保持在第一页和第二页的中间不动.

别忘了 JazzHands 是一个帧动画,所以我们设置参数的解释就是,在 time=0时, imageView 保持在第一页中间, time=1时, imageView 保持在第二页中间,我们只需设置这2个关键帧,其余的 JazzHands 会帮我们搞定.

那么下面这个方法呢?..

[self keepView:self.ifttt onPages:@[@(0),@(1.5)] atTimes:@[@(0),@(1)]]; 

在 time=0时, imageView 保持在第一页中间,在 time=1时, imageView 保持在第二页中间 再偏离中间0.5倍的位置.

具体的实现是,现在 scrollView 滚动10px, imageView 滚动 15px, 所以从第一页滚动到第二页的过程中,感觉 imageView 滚动的距离比较长,滚动的比较快.

所以[self keepView:self.ifttt onPages:@[@(0),@(1.5)] atTimes:@[@(0),@(1)]];这个方法不仅能将 view 保持在某一页面出现,调整参数后,还能制作 X 轴偏移的动画,所以后我们给 view设置约束时,不用设置 X 轴的约束,只需调用此方法即可约束 view 的 X 轴位置.

明白了这点就可以无压力的制作动画了..

Done

所有代码你可以在 Github 中找到

下一篇 我们用 JazzHands+AutoLayout 来模仿 官方 Demo 的效果

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

推荐阅读更多精彩内容