微博红包加载动画

新浪微博的红包加载动画,过年在家里抢红包看到这个效果,就顺手仿照着写了一下。主要还是利用余弦函数曲线的特性实现的。

具体原理是圆球在从左向右移动时时先缩小再放大,圆球从右向左移动时先放大在缩小;然后再加上另一个圆球就实现了这样远近交换的效果。
GitHub地址:https://github.com/mengxianliang/XLDotLoading
XLDot.h

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger,DotDitection)
{
    DotDitectionLeft = -1,
    DotDitectionRight = 1,
};


@interface XLDot : UIView

//移动方向 就两种 左、右
@property (nonatomic,assign) DotDitection direction;
//字体颜色
@property (nonatomic,strong) UIColor *textColor;

@end

XLDot.m

#import "XLDot.h"

@interface XLDot ()
{
    UILabel *_label;
}
@end

@implementation XLDot

-(instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self buildUI];
    }
    return self;
}

-(void)buildUI
{
    self.layer.cornerRadius = self.bounds.size.width/2.0f;
    self.layer.masksToBounds = true;
    
    _label = [[UILabel alloc] initWithFrame:self.bounds];
    _label.textAlignment = NSTextAlignmentCenter;
    _label.font = [UIFont boldSystemFontOfSize:20];
    _label.text = @"¥";
    _label.adjustsFontSizeToFitWidth = true;
    [self addSubview:_label];
}

-(void)setTextColor:(UIColor *)textColor
{
    _textColor = textColor;
    _label.textColor = textColor;
}

@end

XLDotLoading.h

#import <UIKit/UIKit.h>

@interface XLDotLoading : UIView

//显示方法
+(void)showInView:(UIView*)view;
//隐藏方法
+(void)hideInView:(UIView*)view;

-(void)start;

-(void)stop;

@end

XLDotLoading.m

#import "XLDotLoading.h"
#import "XLDot.h"

@interface XLDotLoading ()
{
    NSMutableArray *_dots;
    
    CADisplayLink *_link;
    
    UIView *_dotContainer;
}
@end

@implementation XLDotLoading

//初始化方法
-(instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self buildUI];
        [self buildData];
    }
    return self;
}

//豆的宽度
-(CGFloat)dotWidth
{
    CGFloat margin = _dotContainer.bounds.size.width/5.0f;
    CGFloat dotWidth = (_dotContainer.bounds.size.width - margin)/2.0f;
    return  dotWidth;
}

-(CGFloat)speed
{
    return  2.0f;
}

//初始化两个豆
-(void)buildUI
{
    //初始化存放豆豆的的容器
    _dotContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 50)];
    _dotContainer.center = self.center;
    [self addSubview:_dotContainer];
    
    //一个豆放左 一个豆放右
    _dots = [NSMutableArray new];
    NSArray *dotBackGroundColors = @[[self R:255 G:218 B:134 A:1],[self R:245 G:229 B:216 A:1]];
    NSArray *textColors = @[[self R:255 G:197 B:44 A:1],[self R:237 G:215 B:199 A:1]];
    
    for (NSInteger i = 0; i<textColors.count; i++) {
        CGFloat dotX = i==0 ? 0 : _dotContainer.bounds.size.width - [self dotWidth];
        //初始化开始运动的方向 左边的方向是向右 右边的方向是向左
        DotDitection direction = i==0 ? DotDitectionRight : DotDitectionLeft;
        XLDot *dot = [[XLDot alloc] initWithFrame:CGRectMake(dotX, 0, [self dotWidth],[self dotWidth])];
        dot.center = CGPointMake(dot.center.x, _dotContainer.bounds.size.height/2.0f);
        dot.layer.cornerRadius = dot.bounds.size.width/2.0f;
        dot.backgroundColor = dotBackGroundColors[i];
        dot.direction = direction;
        dot.textColor = textColors[i];
        [_dotContainer addSubview:dot];
        [_dots addObject:dot];
    }
}

//初始化定时刷新
-(void)buildData
{
    _link = [CADisplayLink displayLinkWithTarget:self selector:@selector(reloadView)];
}

//开始动画
-(void)start
{
    [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

//停止动画
-(void)stop
{
    [_link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

//刷新UI
-(void)reloadView
{
    XLDot *dot1 = _dots.firstObject;
    
    XLDot *dot2 = _dots.lastObject;
    
    //改变移动方向、约束移动范围
    //移动到右边距时
    if (dot1.center.x >= _dotContainer.bounds.size.width - [self dotWidth]/2.0f) {
        CGPoint center = dot1.center;
        center.x = _dotContainer.bounds.size.width - [self dotWidth]/2.0f;
        dot1.center = center;
        dot1.direction = DotDitectionLeft;
        dot2.direction = DotDitectionRight;
        [_dotContainer bringSubviewToFront:dot1];
    }
    //移动到左边距时
    if (dot1.center.x <= [self dotWidth]/2.0f) {
        dot1.center = CGPointMake([self dotWidth]/2.0f, dot2.center.y);
        dot1.direction = DotDitectionRight;
        dot2.direction = DotDitectionLeft;
        [_dotContainer sendSubviewToBack:dot1];
    }
    
    //更新第一个豆的位置
    CGPoint center1 = dot1.center;
    center1.x += dot1.direction * [self speed];
    dot1.center = center1;
    //显示放大效果
    [self showAnimationsOfDot:dot1];
    
    //根据第一个豆的位置确定第二个豆的位置
    CGFloat apart = dot1.center.x - _dotContainer.bounds.size.width/2.0f;
    CGPoint center2 = dot2.center;
    center2.x = _dotContainer.bounds.size.width/2.0f - apart;
    dot2.center = center2;
    [self showAnimationsOfDot:dot2];
}

//显示放大、缩小动画
-(void)showAnimationsOfDot:(XLDot*)dot
{
    CGFloat apart = dot.center.x - _dotContainer.bounds.size.width/2.0f;
    //最大距离
    CGFloat maxAppart = (_dotContainer.bounds.size.width - [self dotWidth])/2.0f;
    //移动距离和最大距离的比例
    CGFloat appartScale = apart/maxAppart;
    //获取比例对应余弦曲线的Y值
    CGFloat transfomscale = cos(appartScale * M_PI/2.0);
    
    
    //向右移动则 中间变大 两边变小
    if (dot.direction == DotDitectionLeft) {
        dot.transform = CGAffineTransformMakeScale(1 + transfomscale/4.0f, 1 + transfomscale/4.0f);
        //向左移动则 中间变小 两边变大
    }else if (dot.direction == DotDitectionRight){
        dot.transform = CGAffineTransformMakeScale(1 - transfomscale/4.0f,1 - transfomscale/4.0f);
    }
}

-(UIColor*)R:(CGFloat)r G:(CGFloat)g B:(CGFloat)b A:(CGFloat)a
{
    return [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a];
}

#pragma mark -
#pragma mark 功能方法

+(XLDotLoading *)getLoadingInView:(UIView *)view {
    
    XLDotLoading *loading = nil;
    for (XLDotLoading *subview in view.subviews) {
        if ([subview isKindOfClass:[XLDotLoading class]]) {
            loading = subview;
        }
    }
    return loading;
}

+(void)showInView:(UIView*)view
{
    XLDotLoading *loading = [[XLDotLoading alloc] initWithFrame:view.bounds];
    [view addSubview:loading];
    [loading start];
}

+(void)hideInView:(UIView *)view
{
    XLDotLoading *loading = [XLDotLoading getLoadingInView:view];
    if (loading) {
        [loading removeFromSuperview];
        [loading stop];
    }
}


@end

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

推荐阅读更多精彩内容