好久沒有更新過博客了,最近公司比較忙,老項目需要換Swift重寫,用了一周左右的時間學習了下Swift,目前正在改寫舊項目,個人對Swift愛不釋手,感覺取代OC就這一兩年內的事,不過老的iOS開發(fā)者也不需要擔心,會OC轉Swift真的像切菜一樣簡單,只需要熟悉下語法就可以,函數(shù)和OC的基本差不多,基本看個4,5個小時就可以直接上手Swift開發(fā)項目,中間不熟悉的寫法只需要百度下即可,相信朋友們都會喜歡上Swift的,嘮叨的有點跑題了,廢話不多說,直接上代碼!
由于公司項目的需求,想要達到和手機QQ未讀信息一樣的動畫效果,周末試著寫了一下,效果基本實現(xiàn)了,不過還有些Bug正在修改中,代碼用OC寫的,如果需要Swift代碼的朋友可以發(fā)個私信給我,等我完善玩Swift代碼發(fā)給你,先發(fā)一下效果圖給大家參考下

效果gif

效果gif

效果gif
先說一下大體的思路吧,控件是繼承Button寫的,并且在button的下面添加一個小的圓,給button添加拖拽手勢,根據(jù)倆個圓的中心點算出拉動的距離,拖動的距離越大小圓的半徑越小(
勾股定理
)-
這個動畫最大的難點在畫倆個畫出倆個圓之間的不規(guī)則的矩形,通過下面的這個公式可以計算出倆個圓的直徑上的四個點和中間的2個點的貝塞爾控制點的point,參照下面圖片
根據(jù)倆個圓的中心點算出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內部實現(xiàn)的代碼,所以不可以直接在drawRect中直接繪制,超出范圍的會被裁剪掉,需要CAShapeLayer來繪制
self.shapeLayer.path = [self pathWithBigCirCleView:self
smallCirCleView:_samllCircleView].CGPath;
- 從寫按鈕的setHighlighted:方法,在里面實現(xiàn)長按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
時候銷毀所有的對象,播放消失動畫設置大圓距離小圓最大的距離,根據(jù)手勢的staus,在拖拽的函數(shù)里判斷距離是否超過最大的距離,超過最大距離時候移除shapeLayer隱藏小圓
還有一些細節(jié)在此就不一一列舉了
我自己大體的思路就是如此
下面是OC的源碼,希望小手能順便點一下右上角的??Star
如果朋友們有什么問題可以直接留言,我會看到回復
代碼下載