即刻App 點贊數(shù)字變化動畫效果的實現(xiàn)

前言

久違的再次動筆寫博客。。。

說明

從一年前開始使用即刻這款A(yù)PP, 一直覺得它的細節(jié)做的特別好, 最近開始動筆,仿寫它的一些效果實現(xiàn), 從點贊數(shù)字變化開始。

Demo 地址

https://github.com/94haox/AnimationNumber

實現(xiàn)

開始

先看下效果(GIF圖,沒做好需要等一等,當(dāng)然我建議是直接下載Demo,運行。。。 )


效果圖

在點贊的時候, 點贊數(shù)+1, 或者取消點贊 -1, 只在個位(當(dāng)然臨界點是牽扯到各個位)實現(xiàn) 向上平滑而出, 或者向下平滑而出的動畫

思考

  • 首先點贊數(shù)是一個字符串,我們需要對字符串中的單個字符進行操作,那么首先, 我們需要將字符串分割,便于操作;
  • 分割成單個字符后, 需要用UILabel 顯示, 意味著需要相同個數(shù)的Label;
  • 對Label做動畫;

動手敲代碼

新建一個類 繼承于UIView, AnimationNumber;

添加一些便于自定義label的屬性

// 顯示label的字體
@property (nonatomic, strong)UIFont *numberFont;
// 顯示label的顏色
@property (nonatomic, strong)UIColor *numberColor;
// 用于接收字符串
@property (nonatomic, copy) NSString *currentNumber;

在 Extension 中添加一些我們不需要暴露在外的屬性

// 之前顯示的數(shù)字
@property (nonatomic, strong) NSMutableArray<NSString *> *oldNumbers;
// 之前顯示的Label
@property (nonatomic, strong) NSMutableArray<UILabel *> *oldLabelList;
// 當(dāng)前顯示的數(shù)字
@property (nonatomic, strong) NSMutableArray<NSString *> *currentNumbers;
// 當(dāng)前顯示的Label
@property (nonatomic, strong) NSMutableArray<UILabel *> *currentLabelList;
@property (nonatomic, strong) UIView *contentView;

在第一次接收字符串的時候, oldNumbers,oldLabelList 應(yīng)該是空的;只有在第二次接收的時候才會儲存上一次的分割后的number, 和Label;

初始化

- (instancetype)initWithFrame:(CGRect)frame{
  if (self = [super initWithFrame:frame]) {
    self.oldNumbers = [NSMutableArray arrayWithCapacity:1];
    self.currentNumbers = [NSMutableArray arrayWithCapacity:1];
    self.oldLabelList = [NSMutableArray arrayWithCapacity:1];
    self.currentLabelList = [NSMutableArray arrayWithCapacity:1];

    // contentView 寫成了懶加載, 看Demo
    [self addSubview:self.contentView]; 
  }
  return self;
}

下面說明, 主要實現(xiàn)的方法;

 // 分割 字符串
- (void)carveUpNumberWith:(NSString *)number{
  NSMutableArray<UILabel *> *labelsList = [NSMutableArray array];
  NSMutableArray<NSString *> *numbersList = [NSMutableArray array];
  for (int i = 0; i < number.length; i++) {
    NSString *stringItem = [number substringWithRange:NSMakeRange(i, 1)];
    // Label創(chuàng)建 看Demo
    UILabel *label = [self createLabels:stringItem];
    CGRect frame = label.frame;
    // 第一個Label
    frame.origin.x = labelsList.count > 0 ? CGRectGetMaxX(labelsList.lastObject.frame) : 0;
    frame.origin.y = 0;
    label.frame = frame;
    [labelsList addObject:label];
    [numbersList addObject:stringItem];
  }
  self.currentLabelList = labelsList;
  self.currentNumbers = numbersList;
}

最重要的方法


實現(xiàn)動畫
- (void)updateLabelsWithNumber:(NSString *)number{
    //  通過oldLabelList.count判斷是否是第一次接收字符串
  if (self.oldLabelList.count > 0) {
    // 判斷兩次數(shù)字的差別, 從最后一位開始比較
    NSInteger length = number.length;
    NSInteger oldLength = self.oldLabelList.count;
    for (int i = 0; i < self.currentNumbers.count; i ++) {
      NSString *item = [number substringWithRange:NSMakeRange(length - i-1, 1)];
      UILabel *label = self.currentLabelList[length-i-1];
      // 判斷 防止數(shù)組越界
      if (i < self.oldLabelList.count) {
        NSString *oldItem = self.oldNumbers[oldLength - i-1];
        UILabel *oldLabel = self.oldLabelList[oldLength-i-1];
        // 判斷相同位置, 是否數(shù)字相同
        if (![oldItem isEqualToString:item]) {
        //  相同位置, 單個數(shù)字, 現(xiàn)在比之前大, 動畫從上往下, 現(xiàn)在比之前小則從下往上
          CGRect frame = label.frame;
          if (oldItem.integerValue < item.integerValue) {
           frame.origin.y = - label.frame.size.height;
          }else{
           frame.origin.y = label.frame.size.height;
          }
          label.frame = frame;

          [UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            CGRect frame = label.frame;
            frame.origin.y = 0;
            label.frame = frame;

            CGRect oldFrame = oldLabel.frame;
            if (oldItem.integerValue < item.integerValue) {
              oldFrame.origin.y = oldLabel.frame.size.height;
            }else{
              oldFrame.origin.y = -oldLabel.frame.size.height;
            }
            oldLabel.frame = oldFrame;
          } completion:^(BOOL finished) {
            // 做完動畫, 移出視圖
            [oldLabel removeFromSuperview];
          }];
        }else{
          [oldLabel removeFromSuperview];
        }
        
      }else{
        CGRect frame = label.frame;
        frame.origin.y = - label.frame.size.height;
        label.frame = frame;
        
        [UIView animateWithDuration:animationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
          CGRect frame = label.frame;
          frame.origin.y = 0;
          label.frame = frame;
        } completion:nil];
        
      }
    }
  }
  
  // 當(dāng)之前的數(shù)值比較大時, 移除多出的位數(shù)
  if (self.oldLabelList.count > self.currentLabelList.count) {
    for (int i = 0; i < self.oldLabelList.count - self.currentLabelList.count; i ++) {
      UILabel *label = self.oldLabelList[i];
      [label removeFromSuperview];
    }
  }
  
  self.oldLabelList = self.currentLabelList;
  self.oldNumbers = self.currentNumbers;
  
}

結(jié)束

其實效果挺簡單, 當(dāng)然實現(xiàn)也挺簡單, 可能有更好的實現(xiàn)方法, 希望看到的朋友,告訴我。。。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,618評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,153評論 25 708
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,422評論 4 61
  • synthesize 和 dynamic區(qū)別 ? @synthesize 的語義是如果你沒有手動實現(xiàn) setter...
    英雄出少年閱讀 165評論 0 0
  • 那日 你踱水而來,含情脈脈 我執(zhí)卷繾綰,淡淡一笑 那月 你水邊牧馬,林下飲茶 我溪里浣紗,洗手羹湯 那...
    剪痕閱讀 278評論 0 7

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