JazzHands + AutoLayout 基本使用

在上一篇文章中,我們已經(jīng)能用JazzHands做出一個(gè)完整的 Guide 動(dòng)畫了,但是這個(gè)動(dòng)畫還有一些不足.

  • 它是用 Frame 來(lái)布局的,在不同的機(jī)型上適配起來(lái)很麻煩

JazzHands 2.0已經(jīng)解決了這個(gè)問(wèn)題
用 AutoLayout 來(lái)布局,用 IFTTTConstraintConstantAnimation 和 IFTTTConstraintMultiplierAnimation來(lái)做動(dòng)畫
使用起來(lái)代碼會(huì)復(fù)雜一些,但是對(duì)屏幕適配,屏幕旋轉(zhuǎn), iPad split-screen 支持的更好.

使用 IFTTTAnimatedPagingScrollViewController

IFTTTAnimatedPagingScrollViewController 內(nèi)部Override 下面這2個(gè)方法,結(jié)合 AutoLayout 完成適配.

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

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

接下來(lái)我們使用AutoLayout 和 JazzHands做一個(gè)簡(jiǎn)單的 透明度漸變動(dòng)畫.

創(chuàng)建一個(gè)空 ViewController 繼承 IFTTTAnimatedPagingScrollViewController
這是 JazzHands 提供給我們的方便結(jié)合使用 AutoLayout 制作動(dòng)畫的類,以后我們使用 AutoLayout 做動(dòng)畫直接繼承這個(gè)類就可以了,它已經(jīng)幫我們初始化好了 scrollView,contentView,Animator

在類擴(kuò)展中只需添加我們動(dòng)畫的 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 會(huì)遮住內(nèi)容,加上這行保證內(nèi)容顯示在 navigationBar 下面,一般來(lái)說(shuō)我們的 Guide 動(dòng)畫都是全屏的,不需要加這行
    [self.v mas_makeConstraints:^(MASConstraintMaker *make) {
        make.width.height.equalTo(@30); //固定 view 寬高為30
    }];
    
    [self keepView:self.v onPage:0]; //keepView 下面會(huì)說(shuō)到
    
    IFTTTAlphaAnimation *alpha=[IFTTTAlphaAnimation animationWithView:self.v];
    [self.animator addAnimation:alpha];
    
    [alpha addKeyframeForTime:0 alpha:1];
    [alpha addKeyframeForTime:1 alpha:0]; //注意 time 是 1
}

運(yùn)行一下,效果如圖

JazzHands+AutoLayoutDemo.gif

上面的代碼和我們前2篇文章使用 Frame 布局制作動(dòng)畫類似,但有3點(diǎn)不同.

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

關(guān)于第一點(diǎn) : 將 View 添加到了 contentView中.

引用一段 斯坦福大學(xué)公開課:iOS 7應(yīng)用開發(fā)

圖片較大 - scrollView.gif
圖片較大 - scrollView.gif

gif 中手機(jī)屏幕是全屏的 scrollView, 后面的圖片是 contentView, 我們將contentView 用scrollView.addsubView(contentView), 添加到 scrollView 中,再將其他所有需要展示的 View 添加到 contentView 中, scrollView 是為后面的 ContentView提供一個(gè)窗口
我們手指滑動(dòng)屏幕, scrollView.contentOffset.x 改變,我們能看到的 contentView 的內(nèi)容看起來(lái)跟著滾動(dòng)變化了,但實(shí)際上 contentView 的位置是固定的.

我們?cè)诶^承 IFTTTAnimatedPagingScrollViewController時(shí)contentView,scrollView 已經(jīng)被初始化好了,我們只需將需要展示的 view 添加到 self.contentView 中即可

關(guān)于第二點(diǎn)

既然我們使用 AutoLayout, 那么對(duì) view 進(jìn)行布局,設(shè)置動(dòng)畫,就都要使用 AutoLayout, 這里使用 Mansonry 開源庫(kù)來(lái)設(shè)置約束.

關(guān)于第三點(diǎn) : addKeyframeForTime:1 time 是1.

之前我們使用 Frame

//創(chuàng)建一個(gè)透明度動(dòng)畫
    IFTTTAlphaAnimation *alpha=[IFTTTAlphaAnimation animationWithView:self.v];
    //將所有動(dòng)畫添加到 animator 中
    [self.animator addAnimation:alpha];

    //添加2個(gè)幀,在 scrollView 從 0 滾動(dòng)到 200 時(shí), 淡出我們的 View
    [alpha addKeyframeForTime:0 alpha:1.0];
    [alpha addKeyframeForTime:200 alpha:0.0];
    
    
    //scrollView 代理
    -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
        [self.animator animate:scrollView.contentOffset.x];
    }
}

現(xiàn)在我們使用 AutoLayout 和 IFTTTAnimatedPagingScrollViewController

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

IFTTTAnimatedPagingScrollViewController內(nèi)部幫我們做了scrollView.contentOffset.xtime 的轉(zhuǎn)換
具體實(shí)現(xiàn)類似 :

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

它將 contentOffset.x轉(zhuǎn)換為 頁(yè)面寬度的百分比,

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

所以這段代碼我們?cè)O(shè)置的動(dòng)畫是, scrollView 從第一頁(yè)滾動(dòng)到第二頁(yè), view 的透明度從1變化到0

[keepView:onPage:]方法

如果你細(xì)心的話,可以發(fā)現(xiàn)上面的例子中,我們并沒(méi)有設(shè)置 x 軸的約束,但是紅色方塊的位置在 X 軸居中,
就是因?yàn)?code>[self keepView:self.v onPage:0];,這行代碼

我們寫一個(gè)例子來(lái)看看這個(gè)方法及其重載方法的作用,

新建一個(gè)空白 ViewController, 繼承自 IFTTTAnimatedPagingScrollViewController

類擴(kuò)展中

@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 一個(gè)方法,告訴父類我們需要的頁(yè)數(shù)

-(NSUInteger)numberOfPages{
    return 4;
}

運(yùn)行一下,效果如圖

KeepViewDemo.gif

我們并沒(méi)有給 ITFFF imageView設(shè)置任何的動(dòng)畫和約束,但是它在 X軸居中,
就是因?yàn)槲覀冊(cè)O(shè)置了[self keepView:self.ifttt onPage:0];,讓 imageView 出現(xiàn)在第一頁(yè),

我們繼續(xù)使用它的重載方法..

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

運(yùn)行結(jié)果如下..

KeepViewDemo_2.gif

注意看下面的 scrollIndicator, 即使我滑動(dòng)到第二頁(yè),它還是保持在屏幕中間的位置,

繼續(xù)修改代碼為

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

這個(gè)運(yùn)行的結(jié)果和上面一樣,其實(shí)我們調(diào)用 [self keepView:self.ifttt onPages:@[@(0),@(1)]];時(shí),
內(nèi)部會(huì)調(diào)用它的重載方法
[self keepView:self.ifttt onPages:@[@(0),@(1)] atTimes:@[@(0),@(1)]];,
所以這2個(gè)方法的效果是一樣的

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

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

運(yùn)行結(jié)果如下

KeepViewDemo_3.gif

這個(gè)運(yùn)行結(jié)果看起來(lái)有點(diǎn)詭異,
先來(lái)解釋這個(gè)方法,

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

調(diào)用這個(gè)方法起到的效果是, ImageView 會(huì)保持在第一頁(yè)和第二頁(yè)的中間,
當(dāng)我們調(diào)用這個(gè)方法時(shí),內(nèi)部會(huì)給 imageView 和 contentView 添加一個(gè) X 軸的約束,讓 imageView 保持在頁(yè)面中間,
onPages:@[@(0),@(1)] 就代表保持在第一二頁(yè)的中間, atTimes:@[@(0),@(1)] 代表2個(gè)時(shí)間點(diǎn),

它內(nèi)部的實(shí)現(xiàn)是在 scrollView 滾動(dòng)時(shí),將 scrollView.contentOffset.x 累加給 imageView 和 contentView 的約束的 constant 上,也就是 scrollView 滾動(dòng)多少, imageView 也滾動(dòng)多少,所以產(chǎn)生的效果就是 imageView 一直保持在第一頁(yè)和第二頁(yè)的中間不動(dòng).

別忘了 JazzHands 是一個(gè)幀動(dòng)畫,所以我們?cè)O(shè)置參數(shù)的解釋就是,在 time=0時(shí), imageView 保持在第一頁(yè)中間, time=1時(shí), imageView 保持在第二頁(yè)中間,我們只需設(shè)置這2個(gè)關(guān)鍵幀,其余的 JazzHands 會(huì)幫我們搞定.

那么下面這個(gè)方法呢?..

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

在 time=0時(shí), imageView 保持在第一頁(yè)中間,在 time=1時(shí), imageView 保持在第二頁(yè)中間 再偏離中間0.5倍的位置.

具體的實(shí)現(xiàn)是,現(xiàn)在 scrollView 滾動(dòng)10px, imageView 滾動(dòng) 15px, 所以從第一頁(yè)滾動(dòng)到第二頁(yè)的過(guò)程中,感覺(jué) imageView 滾動(dòng)的距離比較長(zhǎng),滾動(dòng)的比較快.

所以[self keepView:self.ifttt onPages:@[@(0),@(1.5)] atTimes:@[@(0),@(1)]];這個(gè)方法不僅能將 view 保持在某一頁(yè)面出現(xiàn),調(diào)整參數(shù)后,還能制作 X 軸偏移的動(dòng)畫,所以后我們給 view設(shè)置約束時(shí),不用設(shè)置 X 軸的約束,只需調(diào)用此方法即可約束 view 的 X 軸位置.

明白了這點(diǎn)就可以無(wú)壓力的制作動(dòng)畫了..

Done

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

下一篇 我們用 JazzHands+AutoLayout 來(lái)模仿 官方 Demo 的效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容