iOS轮播图:CADisplayLink实现轮播和自定义动画的时间曲线算法(渐入渐出等)

轮播图默认样式

Demo地址:https://github.com/FlashHand/BuffKit

运行BuffDemo里的工程,找到轮播图即可查看。

使用简介:


{
    BFLoopView *bfLoopView;
}

//.m

NSMutableArray *btnArr=[NSMutableArray new];
for (int i=0; i<3; i++) {
        UIButton *btn=[[UIButton alloc]initWithFrame:CGRectMake(0, 0, self.view.width, 220)];
        [btn setTitle:[NSString stringWithFormat:@"Button:%d",i] forState:UIControlStateNormal];
        UIImage *img=[UIImage imageNamed:[NSString stringWithFormat:@"loop%d.jpg",i+1]];
        [btn setBackgroundImage:img forState:UIControlStateNormal];
        [btn setBackgroundColor:[UIColor lightGrayColor]];
        [btn addTarget:self action:@selector(loopViewClickAction:) forControlEvents:UIControlEventTouchUpInside];
        [btn setTag:i];
        [btnArr addObject:btn];
    }
//period是播放周期,duration是滑动动画的持续时间.
bfLoopView=[BFLoopView loopViewWithItems:btnArr 
frame:CGRectMake(0, 64, self.view.width, 220) loopPeriod:4
animationDuration:1 
animationStyle:BuffLoopViewAnimationStyleEasyInOut 
indexChanged:^(NSInteger loopIndex) {
  //当前页面索引变化时执行的回调
    }];
    [self.view addSubview:bfLoopView];
    [bfLoopView setShouldAnimation:YES];//开始并允许自动轮播,
    [bfLoopView setShouldAnimation:NO];//停止并禁止自动轮播,

实现自动轮播的思路:

1.使用无限宽的UISCrollView(实际上是INT16_MAX+1

[loopView setPagingEnabled:YES];
        [loopView setBounces:NO];
        [loopView setContentSize:CGSizeMake(frame.size.width*(INT16_MAX+1), frame.size.height)];
        [loopView setShowsVerticalScrollIndicator:NO];
        [loopView setShowsHorizontalScrollIndicator:NO];
        [loopView setDirectionalLockEnabled:YES];

2.放置所有视图,这里我决定把视图放置在UISCrollView偏居中的位置,下面是计算方法,这样算的好处是:一是能确保初始位置是偏居中的,二是确保初始位置的偏移量是单页宽度的整数倍


CGFloat initialOffsetX=floor(loopView.contentSize.width/2.0/loopItems.count/loopView.width)*loopView.width*loopItems.count;
[loopView setContentOffset:CGPointMake(initialOffsetX, 0)];

3.控制自动轮播
通过CADisplayLink+NSTimer实现对UIScrollView的准确控制,
若使用UIView或UIScrollView自带的动画则动画的时间曲线不好控制,轮播时可能会卡住且没法处理。
NSTimer控制何时开始播放动画
CADisplayLink配合CACurrentMediaTime()控制动画的播放过程
具体请查看demo

4.关于动画的时间曲线,时间曲线是通过这个block去计算的
static void(^_bfAnimationFunction)(CGFloat p);

当你需要自定义时间曲线函数的时候可以通过调用
setLoopAnimationStyle:BuffLoopViewAnimationStyleCustom
然后使用“
-(void)setCustomAnimationStyle:(void(^)(CGFloat p))animationFunction;”来实现自定义的时间曲线,且该函数必须满足f(0)=0,f(1)=1

预先设置block可以避免在CADisplayLink的触发的函数里做多余的判断,导致性能降低

下面是不同的时间曲线的映射方法:
算法参考:
http://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html
https://github.com/danro/jquery-easing/blob/master/jquery.easing.js

//easing 算法
    //x ∈ [0,1]
    //Linear:f(x)=x
    BuffLoopViewAnimationStyleLinear = 1,
    //easyIn:f(x)=-cos(x * (M_PI/2)+1
    BuffLoopViewAnimationStyleEasyIn = 2,
    //easyInOut:f(x)=-0.5*cos(M_PI*x)+0.5
    BuffLoopViewAnimationStyleEasyInOut = 3,
    //easyOut:f(x)=sin(x * M_PI/2)
    BuffLoopViewAnimationStyleEasyOut = 4,
    //custom:使用 "-(void)setAnimationStyle:(void(^)(CGFloat p))animationFunction;"自定义切换效果。
    //注意,必须满足f(0)=0,f(1)=1
    BuffLoopViewAnimationStyleCustom = 100,

5.添加页面切换回调:
static void(^_bfIndexChanged)(NSInteger i);
默认会显示一个UIPageControl,若不需要刻意隐藏掉然后利用_bfIndexChanged获取页面切换情况。

你可以直接运行demo,找到LoopViewController查看轮播图的使用方式。

如果你有任何问题或意见,欢迎通过简书留言: )

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容