自定义控件 -- 点赞动画效果

《最美有物》中的点赞效果大家可以看下,在简书上也看到过安卓版本的。分析它的动画效果,最近,利用自己闲暇时间用OC做了个Demo,先看下Demo运行效果:


程序运行效果.gif
页面展示及注意:
  • 默认都是白色,并且也都是默认图片。
  • 当点击某一个视图时候,两个表情都要上升,利用时间也一样。下降也一样。
  • 点击一个视图,背景设置为黄色,另一个表情图片还原为默认图片,背景设置成白色。
  • 点击之后再下降到最初位置的image是动画中最后一张image。
  • 占比发生改变,占比字样随着PLSmileView高度变化而变化,其字样透明度也在不断发生变化。占比字样的NSTextAlignmentCenter设置。
  • 大背景PLBackView的透明度也在变化。
  • “喜欢”被点击之后,上升到最高点时候,会有个星星闪烁。
大背景文件: PLBackView.h 和 PLBackView.m
笑脸的封装文件:PLSmileView.h 和 PLSmileView.m

引用:(两步即可)

1、在控制器视图添加:
  • 就按例子所说,计算比例之前就先知道无感人数 \ 喜欢人数 \ 总人数(无感 + 喜欢)。

  • DislikeCount:无感人数

  • likeCount:喜欢人数,比例值在内部计算。

  • [[UIColor blackColor] colorWithAlphaComponent:0] 背景透明,而子视图不透明。参照:iOS 父子视图的hidden\Alpha\Opaque\clearColor影响简介

    // 添加视图  24是无感的人数  75是喜欢的人数
    PLBackView *backView = [PLBackView backViewWithDislikeCount:24 likeCount: 75];
    backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
    backView.frame = self.view.bounds;
    [self.view addSubview:backView];
    
2、设置属性:
  • 因为backView.frame = self.view.bounds;所以,相对于控制器view的frame值,就是在backView中真正位置。

  • tf: 是添加在控制器view上的文本框

  • disLikeFrame:“无感”frame

  • likeFrame: “喜欢”frame

    // 传入“无感”视图的frame  30是tf与“无感”的间距  20是大图片与“无感”的x方向间距
    backView.disLikeFrame = CGRectMake(CGRectGetMaxX(tf.frame) + 30, CGRectGetMaxY(bgIV.frame) + 20, 0, 0);
    
    // 传入“喜欢”视图的frame  30是“无感”与“喜欢”之间间距 20是大图片与“喜欢”的x方向间距
    backView.likeFrame = CGRectMake(CGRectGetMaxX(backView.disLikeFrame)+ 30, CGRectGetMaxY(bgIV.frame) + 20, 0, 0);
    

demo地址:PLSmileViewDemo

部分注意点: (具体请看demo代码)

1、占比计算

在创建PLBackView实例视图时候,传入了无感 喜欢人数,暂且,用成员变量保存起来,先不计算各自固定占比。等到,任何一个笑脸被点击(点击那个笑脸人数+1)的时候,真正用到动态占比的时候,直接计算动态占比。懒加载!
1.1 保存原始人数

+ (instancetype)backViewWithDislikeCount:(NSUInteger)disLikeCount likeCount:(NSUInteger)likeCount
{
    PLBackView *bv = [[[NSBundle mainBundle] loadNibNamed:@"PLBackView" owner:nil options:nil] lastObject];
    bv.disLikeCount = disLikeCount;
    bv.likeCount = likeCount;
    bv.clickEnable = YES;

   return bv;
}

1.2 在点击了任何一个笑脸,或者来回多次点击时候,占比要设置为0,之后 重新获取。

// 1、比例清空  从懒加载中  获取最新的比例,防止 来回点击喜欢与不喜欢 视图时候,占比发生相应的变化
self.disLikeScale = 0.0;
self.likeScale = 0.0;

// 2、判断点击的是无感  还是  喜欢 视图,相应的人数+1,同时,非点击的那个视图 背景填充设置为非黄色,且,图片赋值成最初图片。
if (smileView.type == PLSmileViewDislikeType) {
    _likeIV.fillYellowColor = NO;
    // 点击的是“不喜欢”  人数加1
    self.disLikeCountMut = self.disLikeCount+1;
    self.likeCountMut = self.likeCount;
    _dislikeIV.maxScaleValue = self.disLikeScale; // 最大值
    // 另一个图片 还原最初的图片
    _likeIV.imageName = @"like_normal";
    
}else
{
    _dislikeIV.fillYellowColor = NO;
    // 点击的是“喜欢”人数加1
    self.likeCountMut = self.likeCount+1;
    self.disLikeCountMut = self.disLikeCount;
    _likeIV.maxScaleValue = self.likeScale; // 最大值
    _dislikeIV.imageName = @"dislike_normal";
}

// 3、 懒加载---比例小数点第三位要满5进1,0.2475 约等于 0.25
#pragma - lazy
- (CGFloat)disLikeScale
{
   if (!_disLikeScale) {
        _disLikeScale = ((CGFloat)_disLikeCountMut / (_disLikeCountMut + _likeCountMut))+0.005; // 0.2475 约等于 0.25
   }
   return _disLikeScale;
 }
- (CGFloat)likeScale
{
   if (!_likeScale) {
    _likeScale = ((CGFloat)_likeCountMut / (_disLikeCountMut + _likeCountMut))+0.005;  // 0.2475 约等于 0.25
   }
   return _likeScale;
}
2、上升动画--定时器

通过定时器使PLSmileView实例视图的占比scale,从0增加到对应的maxScaleValue(无感maxScaleValue为 _disLikeScale, 喜欢maxScaleValue为_likeScale)。上升是共同的时间,下降也是,利用时间相同,这就需要算出,各自变化的幅度是多少。

1、找出高低各自对应的幅度值
CGFloat addOffsetMin = 0.01;
CGFloat addOffsetMax = 0.0;
// 循环次数
NSUInteger count = 0;

CGFloat minScale = MIN(self.disLikeScale, self.likeScale);
count = minScale / addOffsetMin;
addOffsetMax = (1 - minScale) / count;
self.count = count;
self.addOffsetMax = addOffsetMax;
self.addOffsetMin = addOffsetMin;
//开始上升 传scale
__block CGFloat disLikeScale0 = 0.0;
__block CGFloat likeScale0 = 0.0;
[NSTimer scheduledTimerWithTimeInterval:0.01 repeats:YES block:^(NSTimer * _Nonnull timer) {
    
    if (self.disLikeScale < self.likeScale) {  // 喜欢较高 addOffsetMax属于喜欢
        
        disLikeScale0 += addOffsetMin;
        likeScale0 += addOffsetMax;
    }else{         // 不喜欢较高 addOffsetMax属于不喜欢
        
        disLikeScale0 += addOffsetMax;
        likeScale0 += addOffsetMin;
    }
    
    // 传递比例  不断上升
    _dislikeIV.scale = disLikeScale0;
    _likeIV.scale = likeScale0;
    
    
    // 字体的alpha变化
    self.fontAlpha += (CGFloat)1/count;
    // 不断上升的过程中  比例字数位置 也在不断上升
    [self setNeedsDisplay];
    
    
    // 上升到最高点就停止计时器
    if (disLikeScale0 >= _disLikeScale && [timer isValid]) {
        [timer invalidate];
        timer = nil;
        
        
    }
  
    
}];

2、在PLSmileView.m内
/// 不断改变的比例
- (void)setScale:(CGFloat)scale
{
    _scale  = scale;

  // 高度 y值随着变化
   self.height = (scale <= 0?_originalH:_originalH + MAXHEIGHT * scale);
   self.y = _originalY - MAXHEIGHT * scale;
   // 绘制
   [self setNeedsDisplay];
}
3、PLsmileView实例视图上升--[self setNeedsDisplay];
1,画背景圆角矩形框  self.color指填充的颜色
 if (_scale == 0) {
    self.color = [UIColor whiteColor];
}

// 画实心背景 圆角边框
UIBezierPath *borderB = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.width * 0.5];
borderB.lineWidth = 5;  // 边框宽度
[self.color setFill];
[[UIColor greenColor] setStroke]; // 描边颜色
[borderB fill];
[borderB stroke];

// 哭脸  与  笑脸  imageView 始终处在顶端  2.5是表情imageView 与 其父视图self的y值差距(imageView是addSubview到self上的)
self.imageIv.centerX = self.width * 0.5;
self.imageIv.y = 2.5;
4、 imageView图片改变

imageView图片不断改变形成动画,图片不多的情况下可以使用animationImages,在图片比较多的情况下,这种方式不会自动清理image,所以 使用了了NSTimer

   // “喜欢”的动画    总27张
    __block int i = 0;
    [NSTimer scheduledTimerWithTimeInterval:0.02 repeats:YES block:^(NSTimer * _Nonnull timer) {
        i++;
        self.imageIv.image = [UIImage imageNamed:[NSString stringWithFormat:@"like_%d", (i + 1)]];
        
        if ((i+1 == 27) && [timer isValid]) {  // NStimer停止
            [timer invalidate];
            timer = nil;
        }
    }];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容