(iOS)實現QQ未讀消息數量彈性按鈕動畫

好久沒有更新過博客了,最近公司比較忙,老項目需要換Swift重寫,用了一周左右的時間學習了下Swift,目前正在改寫舊項目,個人對Swift愛不釋手,感覺取代OC就這一兩年內的事,不過老的iOS開發者也不需要擔心,會OC轉Swift真的像切菜一樣簡單,只需要熟悉下語法就可以,函數和OC的基本差不多,基本看個4,5個小時就可以直接上手Swift開發項目,中間不熟悉的寫法只需要百度下即可,相信朋友們都會喜歡上Swift的,嘮叨的有點跑題了,廢話不多說,直接上代碼!

由于公司項目的需求,想要達到和手機QQ未讀信息一樣的動畫效果,周末試著寫了一下,效果基本實現了,不過還有些Bug正在修改中,代碼用OC寫的,如果需要Swift代碼的朋友可以發個私信給我,等我完善玩Swift代碼發給你,先發一下效果圖給大家參考下

效果gif
效果gif

效果gif
效果gif

效果gif
效果gif
  • 先說一下大體的思路吧,控件是繼承Button寫的,并且在button的下面添加一個小的圓,給button添加拖拽手勢,根據倆個圓的中心點算出拉動的距離,拖動的距離越大小圓的半徑越小(勾股定理)

  • 這個動畫最大的難點在畫倆個畫出倆個圓之間的不規則的矩形,通過下面的這個公式可以計算出倆個圓的直徑上的四個點和中間的2個點的貝塞爾控制點的point,參照下面圖片


    根據倆個圓的中心點算出6個點的坐標
    根據倆個圓的中心點算出6個點的坐標
  • 傳入倆個圓的中心點,計算出6個點的坐標,用UIBezierPath畫出6個點,代碼如下

   - (UIBezierPath *)pathWithBigCirCleView:(UIView *)bigCirCleView  smallCirCleView:(UIView *)smallCirCleView
{
    CGPoint bigCenter = bigCirCleView.center;
    CGFloat x2 = bigCenter.x;
    CGFloat y2 = bigCenter.y;
    CGFloat r2 = bigCirCleView.bounds.size.width / 2;
    
    CGPoint smallCenter = smallCirCleView.center;
    CGFloat x1 = smallCenter.x;
    CGFloat y1 = smallCenter.y;
    CGFloat r1 = smallCirCleView.bounds.size.width / 2;
    
    // 獲取圓心距離
    CGFloat d = [self pointToPoitnDistanceWithPoint:self.samllCircleView.center potintB:self.center];
    CGFloat sinθ = (x2 - x1) / d;
    CGFloat cosθ = (y2 - y1) / d;
    
    // 坐標系基于父控件
    CGPoint pointA = CGPointMake(x1 - r1 * cosθ , y1 + r1 * sinθ);
    CGPoint pointB = CGPointMake(x1 + r1 * cosθ , y1 - r1 * sinθ);
    CGPoint pointC = CGPointMake(x2 + r2 * cosθ , y2 - r2 * sinθ);
    CGPoint pointD = CGPointMake(x2 - r2 * cosθ , y2 + r2 * sinθ);
    CGPoint pointO = CGPointMake(pointA.x + d / 2 * sinθ , pointA.y + d / 2 * cosθ);
    CGPoint pointP = CGPointMake(pointB.x + d / 2 * sinθ , pointB.y + d / 2 * cosθ);
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    // A
    [path moveToPoint:pointA];
    // AB
    [path addLineToPoint:pointB];
    // 繪制BC曲線
    [path addQuadCurveToPoint:pointC controlPoint:pointP];
    // CD
    [path addLineToPoint:pointD];
    // 繪制DA曲線
    [path addQuadCurveToPoint:pointA controlPoint:pointO];
    
    return path;
}
  • 由于是在button內部實現的代碼,所以不可以直接在drawRect中直接繪制,超出范圍的會被裁剪掉,需要CAShapeLayer來繪制
 self.shapeLayer.path = [self pathWithBigCirCleView:self 
smallCirCleView:_samllCircleView].CGPath;
  • 從寫按鈕的setHighlighted:方法,在里面實現長按button是大圓左右晃動的效果
 - (void)setHighlighted:(BOOL)highlighted
{
    [self.layer removeAnimationForKey:@"shake"];

    //長按左右晃動的幅度大小
    CGFloat shake = 10;
    
    CAKeyframeAnimation *keyAnim = [CAKeyframeAnimation animation];
    keyAnim.keyPath = @"transform.translation.x";
    keyAnim.values = @[@(-shake), @(shake), @(-shake)];
    keyAnim.removedOnCompletion = NO;
    keyAnim.repeatCount = MAXFLOAT;
    //左右晃動一次的時間
    keyAnim.duration = 0.3;
    [self.layer addAnimation:keyAnim forKey:@"shake"];
}
  • 給按鈕本身添加一個點擊事件,TouchUpInside時候銷毀所有的對象,播放消失動畫

  • 設置大圓距離小圓最大的距離,根據手勢的staus,在拖拽的函數里判斷距離是否超過最大的距離,超過最大距離時候移除shapeLayer隱藏小圓

  • 還有一些細節在此就不一一列舉了

我自己大體的思路就是如此

下面是OC的源碼,希望小手能順便點一下右上角的??Star
如果朋友們有什么問題可以直接留言,我會看到回復
代碼下載

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,255評論 4 61
  • 羨慕所有在坦然的愛里長大的小孩 像我這種從小到大自己跌倒自己爬起來自己哭完自己擦眼淚的人 別人給得多一點就會惶恐不...
    眼嫂閱讀 359評論 0 0
  • 去年認識了一個年輕姑娘,長相清秀,身材窈窕,身邊不乏小伙子的追求,但是她卻都不放在心上。 一次外出短期培訓的機會,...
    瑪格麗特MM閱讀 710評論 3 6
  • 七月初七,月未曾滿,于是星星很亮。 一夏的溽熱,秋開始有點小意思的時候,七夕充滿性感和溫柔的款款而來。 是愛情太短...
    德魯伊_Druid閱讀 388評論 0 3
  • 1. 初見 百花盛惠空不就,蔭下清潭好個秋。 曾許暖溪送折柳,相忘何作初見留。 2. 再見 粉面青黛妝已朽,拾憶恨...
    宮主閱讀 276評論 0 0