自定義控件 -- 點(diǎn)贊動(dòng)畫(huà)效果

《最美有物》中的點(diǎn)贊效果大家可以看下,在簡(jiǎn)書(shū)上也看到過(guò)安卓版本的。分析它的動(dòng)畫(huà)效果,最近,利用自己閑暇時(shí)間用OC做了個(gè)Demo,先看下Demo運(yùn)行效果:


程序運(yùn)行效果.gif
頁(yè)面展示及注意:
  • 默認(rèn)都是白色,并且也都是默認(rèn)圖片。
  • 當(dāng)點(diǎn)擊某一個(gè)視圖時(shí)候,兩個(gè)表情都要上升,利用時(shí)間也一樣。下降也一樣。
  • 點(diǎn)擊一個(gè)視圖,背景設(shè)置為黃色,另一個(gè)表情圖片還原為默認(rèn)圖片,背景設(shè)置成白色。
  • 點(diǎn)擊之后再下降到最初位置的image是動(dòng)畫(huà)中最后一張image。
  • 占比發(fā)生改變,占比字樣隨著PLSmileView高度變化而變化,其字樣透明度也在不斷發(fā)生變化。占比字樣的NSTextAlignmentCenter設(shè)置。
  • 大背景PLBackView的透明度也在變化。
  • “喜歡”被點(diǎn)擊之后,上升到最高點(diǎn)時(shí)候,會(huì)有個(gè)星星閃爍。
大背景文件: PLBackView.h 和 PLBackView.m
笑臉的封裝文件:PLSmileView.h 和 PLSmileView.m

引用:(兩步即可)

1、在控制器視圖添加:
  • 就按例子所說(shuō),計(jì)算比例之前就先知道無(wú)感人數(shù) \ 喜歡人數(shù) \ 總?cè)藬?shù)(無(wú)感 + 喜歡)。

  • DislikeCount:無(wú)感人數(shù)

  • likeCount:喜歡人數(shù),比例值在內(nèi)部計(jì)算。

  • [[UIColor blackColor] colorWithAlphaComponent:0] 背景透明,而子視圖不透明。參照:iOS 父子視圖的hidden\Alpha\Opaque\clearColor影響簡(jiǎn)介

    // 添加視圖  24是無(wú)感的人數(shù)  75是喜歡的人數(shù)
    PLBackView *backView = [PLBackView backViewWithDislikeCount:24 likeCount: 75];
    backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
    backView.frame = self.view.bounds;
    [self.view addSubview:backView];
    
2、設(shè)置屬性:
  • 因?yàn)閎ackView.frame = self.view.bounds;所以,相對(duì)于控制器view的frame值,就是在backView中真正位置。

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

  • disLikeFrame:“無(wú)感”frame

  • likeFrame: “喜歡”frame

    // 傳入“無(wú)感”視圖的frame  30是tf與“無(wú)感”的間距  20是大圖片與“無(wú)感”的x方向間距
    backView.disLikeFrame = CGRectMake(CGRectGetMaxX(tf.frame) + 30, CGRectGetMaxY(bgIV.frame) + 20, 0, 0);
    
    // 傳入“喜歡”視圖的frame  30是“無(wú)感”與“喜歡”之間間距 20是大圖片與“喜歡”的x方向間距
    backView.likeFrame = CGRectMake(CGRectGetMaxX(backView.disLikeFrame)+ 30, CGRectGetMaxY(bgIV.frame) + 20, 0, 0);
    

demo地址:PLSmileViewDemo

部分注意點(diǎn): (具體請(qǐng)看demo代碼)

1、占比計(jì)算

在創(chuàng)建PLBackView實(shí)例視圖時(shí)候,傳入了無(wú)感 喜歡人數(shù),暫且,用成員變量保存起來(lái),先不計(jì)算各自固定占比。等到,任何一個(gè)笑臉被點(diǎn)擊(點(diǎn)擊那個(gè)笑臉人數(shù)+1)的時(shí)候,真正用到動(dòng)態(tài)占比的時(shí)候,直接計(jì)算動(dòng)態(tài)占比。懶加載!
1.1 保存原始人數(shù)

+ (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 在點(diǎn)擊了任何一個(gè)笑臉,或者來(lái)回多次點(diǎn)擊時(shí)候,占比要設(shè)置為0,之后 重新獲取。

// 1、比例清空  從懶加載中  獲取最新的比例,防止 來(lái)回點(diǎn)擊喜歡與不喜歡 視圖時(shí)候,占比發(fā)生相應(yīng)的變化
self.disLikeScale = 0.0;
self.likeScale = 0.0;

// 2、判斷點(diǎn)擊的是無(wú)感  還是  喜歡 視圖,相應(yīng)的人數(shù)+1,同時(shí),非點(diǎn)擊的那個(gè)視圖 背景填充設(shè)置為非黃色,且,圖片賦值成最初圖片。
if (smileView.type == PLSmileViewDislikeType) {
    _likeIV.fillYellowColor = NO;
    // 點(diǎn)擊的是“不喜歡”  人數(shù)加1
    self.disLikeCountMut = self.disLikeCount+1;
    self.likeCountMut = self.likeCount;
    _dislikeIV.maxScaleValue = self.disLikeScale; // 最大值
    // 另一個(gè)圖片 還原最初的圖片
    _likeIV.imageName = @"like_normal";
    
}else
{
    _dislikeIV.fillYellowColor = NO;
    // 點(diǎn)擊的是“喜歡”人數(shù)加1
    self.likeCountMut = self.likeCount+1;
    self.disLikeCountMut = self.disLikeCount;
    _likeIV.maxScaleValue = self.likeScale; // 最大值
    _dislikeIV.imageName = @"dislike_normal";
}

// 3、 懶加載---比例小數(shù)點(diǎn)第三位要滿(mǎn)5進(jìn)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、上升動(dòng)畫(huà)--定時(shí)器

通過(guò)定時(shí)器使PLSmileView實(shí)例視圖的占比scale,從0增加到對(duì)應(yīng)的maxScaleValue(無(wú)感maxScaleValue為 _disLikeScale, 喜歡maxScaleValue為_(kāi)likeScale)。上升是共同的時(shí)間,下降也是,利用時(shí)間相同,這就需要算出,各自變化的幅度是多少。

1、找出高低各自對(duì)應(yīng)的幅度值
CGFloat addOffsetMin = 0.01;
CGFloat addOffsetMax = 0.0;
// 循環(huán)次數(shù)
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;
//開(kāi)始上升 傳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;
    // 不斷上升的過(guò)程中  比例字?jǐn)?shù)位置 也在不斷上升
    [self setNeedsDisplay];
    
    
    // 上升到最高點(diǎn)就停止計(jì)時(shí)器
    if (disLikeScale0 >= _disLikeScale && [timer isValid]) {
        [timer invalidate];
        timer = nil;
        
        
    }
  
    
}];

2、在PLSmileView.m內(nèi)
/// 不斷改變的比例
- (void)setScale:(CGFloat)scale
{
    _scale  = scale;

  // 高度 y值隨著變化
   self.height = (scale <= 0?_originalH:_originalH + MAXHEIGHT * scale);
   self.y = _originalY - MAXHEIGHT * scale;
   // 繪制
   [self setNeedsDisplay];
}
3、PLsmileView實(shí)例視圖上升--[self setNeedsDisplay];
1,畫(huà)背景圓角矩形框  self.color指填充的顏色
 if (_scale == 0) {
    self.color = [UIColor whiteColor];
}

// 畫(huà)實(shí)心背景 圓角邊框
UIBezierPath *borderB = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.width * 0.5];
borderB.lineWidth = 5;  // 邊框?qū)挾?[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圖片不斷改變形成動(dòng)畫(huà),圖片不多的情況下可以使用animationImages,在圖片比較多的情況下,這種方式不會(huì)自動(dòng)清理image,所以 使用了了NSTimer

   // “喜歡”的動(dòng)畫(huà)    總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;
        }
    }];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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