折疊效果|動畫

前言

為什么我們要做這個效果裝逼炫技??沒有別的了,廢話少說先看看效果


折疊.gif

下方的箭頭主要是來確定翅楼,整個控件的高度尉剩,是隨著折疊而變化的。

分析

1毅臊、首先遇到問題還是先分析理茎。整個控件是一個折疊容器,然后容器里有很多個小的可以折疊的控件褂微,小的折疊控件,折疊的時候我們把錨點移到y(tǒng)=0园爷,然后在旋轉(zhuǎn)180°

錨點位置

2宠蚂、在每一個可旋轉(zhuǎn)的控件我們首先要做的是截圖,把整個一個可能很復雜的控件變?yōu)橐粡?code>imageview這樣方便我們待會做旋轉(zhuǎn)童社。
3求厕、要做出“翻過來”的效果我這里是使用一個模糊效果的imageview加載上面,旋轉(zhuǎn)180°的過程中并不是一次性完成的扰楼,因為我們?nèi)绻峭险郫B呀癣,旋轉(zhuǎn)到90°的時候我們應該是看到控件的背部,所以我們在旋轉(zhuǎn)90°動畫完成的后弦赖,要把“背部”放到最前面项栏,看上去就像翻過去了。
大致的分析就到這兒蹬竖,其中還有很多細節(jié)需要處理

準備

  • 第一步我們要配置好折疊容器中的可折疊元素沼沈,(這個demo中的0、1币厕、2列另、3、4)
/**
 配置折疊元素
 */
- (void)configurationFoldItem {
    self.unfoldArrayM           = [NSMutableArray arrayWithCapacity:self.itemCount];
    for (int  i = 0; i < self.itemCount; i ++ ) {
        CGRect rect             = CGRectMake(0 , i * self.itemHeight, self.itemWidth, self.itemHeight);
        UIImage *image          = [self ai_takeSnapshotWithFrame:rect];
        AIFoldRotatedView *rotatedView      = [[AIFoldRotatedView alloc]initWithFrame:rect Image:image];
//        rotatedView.layer.anchorPoint    = CGPointMake(.5, 0);
//        //測試
//        rotatedView.tag         = i+100;
        rotatedView.delegate    = self;
        [self addSubview:rotatedView];
        //添加到可折疊數(shù)組中
        [self.itemArrayM addObject:rotatedView];
        //保存到展開數(shù)組中
        [self.unfoldArrayM addObject:[NSValue valueWithCGRect:rect]];
    }
    self.contentView.alpha                  = 0.;
}

實現(xiàn)

在自定義一個控件的時候我們不要立馬去實現(xiàn)某一個方法旦装,而是先想一下我們需要什么屬性页衙,需要什么方法,每一個方法需要哪些對應的參數(shù)阴绢。我覺得這才是一個面向?qū)ο缶幊痰乃枷搿?br> 我們需要讓旋轉(zhuǎn)控件做展開或者折疊的效果店乐,所以我們要有展開和折疊的方法,展開是要時間的,所以參數(shù)有duration呻袭,我們的折疊容器中可折疊的控件不止一個要做到一個控件折疊完成后再折疊第二個所以我們有參數(shù)delay

/**
 旋轉(zhuǎn)180度
 
 @param duration 持續(xù)時長
 @param delay 延時
 */
- (void)foldingAnimationMI_PWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay;
/**
 展開旋轉(zhuǎn)180度
 
 @param duration 持續(xù)時長
 @param delay 延時
 */
- (void)unfoldingAnimationMI_PWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay;

在將要折疊和折疊完成后响巢,我們需要做一些事情,比如修改折疊容器的高度或者說修改狀態(tài)棒妨,我這里是使用協(xié)議代理實現(xiàn)的

@protocol AIFoldRotatedViewDelegate<NSObject>

/**
 折疊完成后回調(diào)

 @param roatatedView 折疊控件
 @param anim anim description
 @param flag flag description
 */
- (void)foldRotatedView:(AIFoldRotatedView*)roatatedView animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
/**
 展開完成后回調(diào)
 
 @param roatatedView 折疊控件
 @param anim anim description
 @param flag flag description
 */
- (void)unfoldRotatedView:(AIFoldRotatedView*)roatatedView animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

/**
 將要折疊回調(diào)
 
 @param roatatedView 折疊控件
 
 */
- (void)willfoldRotatedView:(AIFoldRotatedView*)roatatedView;
/**
 將要展開回調(diào)

 @param roatatedView 折疊控件

 */
- (void)willUnfoldRotatedView:(AIFoldRotatedView*)roatatedView;


@end

在我們剛才大致的分析了之后踪古,現(xiàn)在我們看如何實現(xiàn)這些方法
其中最最核心的就是我們要把這個控件旋轉(zhuǎn)一個角度含长,不管是展開還是折疊都是旋轉(zhuǎn)動畫所以我旋轉(zhuǎn)動畫封裝成一個方法

/**
 旋轉(zhuǎn)動畫
 
 @param timing 節(jié)奏
 @param from 開始
 @param to 結束
 @param duration 持續(xù)時長
 @param delay 延時
 */
- (CABasicAnimation*)rotationAnimationTiming:(NSString *)timing from:(CGFloat)from to:(CGFloat)to duration:(NSTimeInterval)duration delay:(NSTimeInterval)delay  {
    CABasicAnimation *rotateAnimation     = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
    rotateAnimation.timingFunction        = [CAMediaTimingFunction functionWithName:timing];
    rotateAnimation.fromValue             = @(from);
    rotateAnimation.toValue               = @(to);
    rotateAnimation.duration              = duration;
    rotateAnimation.delegate              = self;
    rotateAnimation.fillMode              = kCAFillModeForwards;
    rotateAnimation.removedOnCompletion   = NO;
    rotateAnimation.beginTime             = CACurrentMediaTime() + delay;
    return rotateAnimation;
}

接下來我以折疊為例,展開的方法和折疊類似


/**
 折疊旋轉(zhuǎn)180度

 @param duration 持續(xù)時長
 @param delay 延時
 */
- (void)foldingAnimationMI_PWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay {

    [self clearTransform];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.layer.position       = CGPointMake(CGRectGetMidX(self.frame), self.ai_y );
        self.layer.anchorPoint    = CGPointMake(.5, 0);
        if (self.delegate && [self.delegate respondsToSelector:@selector(willfoldRotatedView:)]) {
            [self.delegate willfoldRotatedView:self ];
        }else {
            AILog(@"未設置代理");
        }
    });
    CABasicAnimation *animation1Layer          = [self rotationAnimationTiming:kCAMediaTimingFunctionEaseIn from:0 to:M_PI_2 duration:duration * .5 delay:delay ];
    [animation1Layer setValue:@"foldstarAnimation" forKey:@"name"];
    [self.layer addAnimation:animation1Layer forKey:@"animation1"];
}

1伏穆、大家可以看到我這里并沒有旋轉(zhuǎn)180°拘泞,而是旋轉(zhuǎn)的90°這是因為我在前面講的我們要實現(xiàn)折疊到一半,我們應該看到的是控件的"背面"枕扫,這里我動畫拿到了添加了key/value就是為了確定動畫結束的地方(這個技巧我在下載按鈕|動畫中也有使用)

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    NSString *name = [anim valueForKey:@"name"];
    if ([name isEqualToString:@"foldstarAnimation"]) {//折疊到90°
        // 讓backView到最前面來
        [self bringSubviewToFront:self.backView];
        CABasicAnimation *foldendAnimation          = [self rotationAnimationTiming:kCAMediaTimingFunctionEaseOut from:M_PI_2 to:M_PI duration:anim.duration delay:0 ];
        [foldendAnimation setValue:@"foldendAnimation" forKey:@"name"];
        [self.layer addAnimation:foldendAnimation forKey:nil];
        
    }else if([name isEqualToString:@"foldendAnimation"]){ //折疊完成
//        [self.layer removeAllAnimations];
        [self rotatedXWithAngle:0];
        [self clearTransform];
        if (self.delegate && [self.delegate respondsToSelector:@selector(foldRotatedView:animationDidStop:finished:)]) {
            [self.delegate foldRotatedView:self animationDidStop:anim finished:flag];
        }else {
            AILog(@"未設置代理");
        }
    }
}

當折疊到90°的時候我們把背景圖陪腌,放到前面來,形成一個"看到控件背后的效果"烟瞧,整個180°旋轉(zhuǎn)完成后調(diào)用折疊完成的回調(diào)函數(shù)诗鸭,這里有點要注意,我們要清理layertransform因為我們是有多個可旋轉(zhuǎn)的控件参滴,還原transform在下一個控件旋轉(zhuǎn)的時候錨點就可能出問題强岸,這個特別是在展開的時候體現(xiàn)非常明顯
2、一個控件折疊完成后,需要修改的他的frame和把已經(jīng)折疊的這個控件放在砾赔,讓已經(jīng)折疊這個控件成為上一個控件的子控件
最后折疊完成后層級關系應該是這樣

折疊完成后層級關系

/**
 一個疊完成后回調(diào)

 @param roatatedView 折疊視圖
 @param anim anim description
 @param flag flag description
 */
-(void)foldRotatedView:(AIFoldRotatedView *)roatatedView animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {

    [roatatedView.layer removeAllAnimations];
    NSInteger index    = [self.itemArrayM indexOfObject:roatatedView];
    self.descView      = self.itemArrayM[index-1];
    roatatedView.frame = self.descView.bounds;
    [self.descView addSubview:roatatedView];

}

GitHub上查看源碼蝌箍,你的star是我最大的支持

源碼位置

參考文獻

參考開源庫:popping
folding-cell
參考博客:http://blog.sina.com.cn/s/blog_8f5097be0101b91z.html

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市暴心,隨后出現(xiàn)的幾起案子妓盲,更是在濱河造成了極大的恐慌,老刑警劉巖专普,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悯衬,死亡現(xiàn)場離奇詭異,居然都是意外死亡檀夹,警方通過查閱死者的電腦和手機刃跛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門柱告,熙熙樓的掌柜王于貴愁眉苦臉地迎上來简烘,“玉大人桦沉,你說我怎么就攤上這事∨妓ぃ” “怎么了暇唾?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辰斋。 經(jīng)常有香客問我策州,道長,這世上最難降的妖魔是什么宫仗? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任够挂,我火速辦了婚禮,結果婚禮上藕夫,老公的妹妹穿的比我還像新娘孽糖。我一直安慰自己枯冈,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布办悟。 她就那樣靜靜地躺著尘奏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪病蛉。 梳的紋絲不亂的頭發(fā)上炫加,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音铺然,去河邊找鬼俗孝。 笑死,一個胖子當著我的面吹牛魄健,可吹牛的內(nèi)容都是我干的赋铝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诀艰,長吁一口氣:“原來是場噩夢啊……” “哼柬甥!你這毒婦竟也來了饮六?” 一聲冷哼從身側(cè)響起其垄,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卤橄,沒想到半個月后绿满,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡窟扑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年喇颁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嚎货。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡橘霎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出殖属,到底是詐尸還是另有隱情姐叁,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布洗显,位于F島的核電站外潜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏挠唆。R本人自食惡果不足惜处窥,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玄组。 院中可真熱鬧滔驾,春花似錦谒麦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沽瞭,卻和暖如春迁匠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驹溃。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工城丧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人豌鹤。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓亡哄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親布疙。 傳聞我的和親對象是個殘疾皇子蚊惯,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,077評論 25 707
  • 《裕語言》速成開發(fā)手冊3.0 官方用戶交流:iApp開發(fā)交流(1) 239547050iApp開發(fā)交流(2) 10...
    葉染柒丶閱讀 26,652評論 5 19
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件灵临、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,094評論 4 62
  • 為什么要不開心截型? 我無法自圓其說 這開放性的話題 你的甜言讓筆尖生了銹 斷了魂 不到情非得已 我只是情非得已 為什...
    倩何人換取閱讀 320評論 0 2
  • 阿禾是典型的雙魚座女生宦焦,低調(diào)內(nèi)斂,多愁善感顿涣,喜歡胡思亂想波闹。 在遇見褚柒以前,她總以為自己會沒人愛地孤單一輩子涛碑。 遇...
    吳困困閱讀 861評論 1 10