循環(huán)仿折疊動(dòng)畫

最近項(xiàng)目里有這樣一個(gè)需求:在搜索人的時(shí)候,提示一些信息,這些信息用折疊的方式把一條把上一條推掉,類似立方體翻轉(zhuǎn)。具體效果可以如下圖:

效果圖.gif

剛好的這個(gè)效果在之前一篇博客里看過:iOS動(dòng)畫-Transform和KeyFrame動(dòng)畫,這篇文章大家可以看下具體原理介紹,本篇只說下一些注意點(diǎn)。不過他那個(gè)動(dòng)畫只做一次,產(chǎn)品需要做成循環(huán)的,然后想著看能不能做成可以4個(gè)方向的,就封裝了下,實(shí)現(xiàn)效果如下:

向下.gif

向上.gif
向右.gif
向左.gif

那要封裝的話,就需要提供動(dòng)畫的開始,暫停,結(jié)束的接口,同時(shí)有一個(gè)初始化方法。那么大致就提煉出了以下視圖頭文件:

#import <UIKit/UIKit.h>

//循環(huán)方向
typedef NS_ENUM(NSInteger, CircleDirection) {
    CircleDirectionDown = 0,
    CircleDirectionRight,
    CircleDirectionUp,
    CircleDirectionLeft
} ;

@interface CPPseudoFoldCircleView : UIView
/**
 *  初始化方法
 *
 *  @param frame     視圖大小,最好和內(nèi)容一樣大
 *  @param views     要循環(huán)的那些視圖
 *  @param direction 循環(huán)方向
 *  @param duration  動(dòng)畫時(shí)間
 *
 *  @return instancetype
 */
- (instancetype)initWithFrame:(CGRect)frame circleViews:(NSArray<UIView *> *)views direction:(CircleDirection)direction duration:(NSTimeInterval)duration;

/**
 *  動(dòng)畫開始
 */
- (void)start;
/**
 *  暫停動(dòng)畫
 */
- (void)pause;
/**
 *  停止動(dòng)畫
 */
- (void)stop;
@end

相應(yīng)的實(shí)現(xiàn)文件如下:

#import "CPPseudoFoldCircleView.h"

@interface CPPseudoFoldCircleView ()
@property (nonatomic, strong) NSTimer *timer;//定時(shí)器,用來循環(huán)動(dòng)畫
@property (nonatomic, assign) CircleDirection direction;//循環(huán)方向
@property (nonatomic, strong) NSArray<UIView *> *views;//要循環(huán)的視圖
@property (nonatomic, assign) NSInteger curIndex;//動(dòng)畫結(jié)束時(shí),當(dāng)前顯示的視圖索引
@property (nonatomic, strong) UIView *view1;//做動(dòng)畫的視圖一
@property (nonatomic, strong) UIView *view2;//做動(dòng)畫的視圖二
@end

@implementation CPPseudoFoldCircleView

- (instancetype)initWithFrame:(CGRect)frame circleViews:(NSArray<UIView *> *)views direction:(CircleDirection)direction duration:(NSTimeInterval)duration {
    self = [super initWithFrame:frame];
    if (self) {
        if (views.count < 2) {
            return nil;
        }
        _direction = direction;
        _views = views;
        [self.view1 addSubview:_views[0]];
        [self.view2 addSubview:_views[1]];
        _timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(animationForCircle) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
        _curIndex = 1;
    }
    return self;
}

#pragma mark - others
- (void)animationForCircle {
    CGFloat offset;
    switch (_direction) {
        case CircleDirectionDown:
            offset = -self.view2.frame.size.height / 2.0;//除以2 是因?yàn)镃GAffineTransformMakeScale 縮放是中心縮放,配合平移就一半就到移動(dòng)到視圖邊界了
            break;
        case CircleDirectionRight:
            offset = -self.view2.frame.size.width / 2.0;
            break;
        case CircleDirectionUp:
            offset = self.view2.frame.size.height / 2.0;
            break;
        case CircleDirectionLeft:
            offset = self.view2.frame.size.width / 2.0;
            break;
        default:
            break;
    }
    BOOL isHorisontal = (_direction == CircleDirectionRight) || (_direction == CircleDirectionLeft);
    self.view2.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(isHorisontal ? 0 : 1, isHorisontal ? 1 : 0), CGAffineTransformMakeTranslation(isHorisontal ? offset : 0 , isHorisontal ? 1 : offset));
    CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformMakeScale(isHorisontal ? 0.01 : 1, isHorisontal ? 1 : 0.01), CGAffineTransformMakeTranslation(isHorisontal ? -offset : 0, isHorisontal ? 0 : -offset ));
    [UIView animateWithDuration:self.timer.timeInterval - 0.1 animations:^{//這個(gè)時(shí)間一定比timer間隔時(shí)間要短一點(diǎn)點(diǎn),不然出現(xiàn)動(dòng)畫沒做完,下一個(gè)timer的迭代又來了,出現(xiàn)不符合預(yù)期的效果
        self.view2.alpha = 1;
        self.view1.alpha = 0;
        self.view2.transform = CGAffineTransformIdentity;
        self.view1.transform = transform;
    } completion:^(BOOL finished) {
        if (finished) {
            self.view1.transform = CGAffineTransformIdentity;
            [self bringSubviewToFront:self.view2];
            self.view1.alpha = 1;
            _curIndex = (_curIndex + 1) % self.views.count;
            [self swapView];//動(dòng)畫完后,交換view1和view2,同時(shí)更新view2的內(nèi)容,以備下一個(gè)動(dòng)畫使用
            for (UIView *temp in self.view2.subviews) {
                [temp removeFromSuperview];
            }
            [self.view2 addSubview:_views[_curIndex]];
        }
    }];
}

#pragma mark - public interface 
- (void)start {
    [_timer setFireDate:[NSDate date]];
}

- (void)pause {
    [_timer setFireDate:[NSDate distantFuture]];
}
- (void)stop {
    [_timer invalidate];
    _timer = nil;
}

#pragma mark - getters / setters
- (UIView *)view2 {
    if (!_view2) {
        _view2 = [[UIView alloc]initWithFrame:self.bounds];
        _view2.backgroundColor = [UIColor whiteColor];
        [self addSubview:_view2];
    }
    return _view2;
}

- (UIView *)view1 {
    if (!_view1) {
        _view1 = [[UIView alloc] initWithFrame:self.bounds];
        _view1.backgroundColor = [UIColor whiteColor];
        [self addSubview:_view1];
    }
    return _view1;
}

#pragma mark - others 
- (void)swapView {
    UIView *view = self.view1;
    self.view1 = self.view2;
    self.view2 = view;
}
@end

以上就是完整的實(shí)現(xiàn)代碼,說明兩個(gè)注意點(diǎn):

  1. offset之所以要除以2,是因?yàn)镃GAffineTransformMakeScale是中心縮放的,縮放完視圖已經(jīng)居中了,要移到邊界只需要平移一半就可以了
  2. 動(dòng)畫時(shí)間一定比timer間隔時(shí)間要短一點(diǎn)點(diǎn),不然出現(xiàn)動(dòng)畫沒做完,下一個(gè)timer的迭代又來了,出現(xiàn)不符合預(yù)期的效果
    好了,需要的同學(xué)自行copy吧_
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,001評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,245評(píng)論 4 61
  • 我很努力的想寫好這條信息! 可語言在此刻顯得特別蒼白無力! 2015年9月,我給一歲的寶寶斷奶,開啟了創(chuàng)業(yè)之路,理...
    梁明月創(chuàng)業(yè)筆記閱讀 194評(píng)論 5 4
  • 暮春三月,江南草長,回眸處,云燕呢喃似無聲。——《暮春》 一幅畫面展示溫情時(shí)光。
    桔紗閱讀 560評(píng)論 0 9
  • 早起醒來去黃河賓館找老舅,早餐的熱面皮真難吃,沒有家里的好。酸豆腐一直吃不慣,可能還是不適應(yīng)這種豪放的吃法。 到了...
    南詔閱讀 219評(píng)論 0 0

友情鏈接更多精彩內(nèi)容