? ? ? ?今天跨年,就在跨年中寫篇博客吧。因為從上海轉戰廣州,在廣州認識的人太少,所以即使是跨年也沒什么事,所以暫時只和技術為伴。先看一下動畫效果,源代碼鏈接:https://github.com/ZhengYaWei1992/QQStickAnimation
? ? ? ?以上這種效果可能在消息提示的時候會使用到,如即時通訊的消息提示按鈕或者用于代替主界面的badgeValue。
? ? ? ? 先剖析一下這個動畫的結構,表面上看起來主要部分是一個帶有數字的紅色控件模塊,外加一個爆炸的動畫(說明:爆炸的實際上是想做成動畫效果的,無奈找不到合適的素材,所以用??代替)。實際上紅色的部分主要是由三部分組成,分別為:帶有數字的按鈕UIButton、由一個路徑轉換而成的CAShapeLayer形變效果、形變效果圖的尾端的另一個紅色的圓形UIView。這里要注意,形變效果的另一末尾端是一個紅色的圓形UIView,只是有一半和形變圖形重疊。隨著圓形UIButton拖動距離增加,紅色的圓形UIView的半徑組件變小,當距離超過一個特定范圍的時候,紅色的圓形UIView以及形變的CAShapeLayer會消失。最后松開手指的時候會出現爆炸??的動畫。
? ? ? ? 再說下這種動畫所用到的技術。
? ? ? ? 一、毫無疑問首先會用到拖動手勢,很多拖動邏輯的都是在UIPanGestureRecognizer的手勢事件中進行判斷的。
? ? ? ? 二、運用數學中的股股定理計算重要的點坐標。然后通過UIBezierPath繪制填充路徑。下面會詳細講解如何計算重要點的坐標值。
? ? ? ? 三、CAShapeLayer的應用,主要是把路徑轉換成圖形,也就是效果圖中的形變效果。其實核心代碼也就只是一句。
? ? 具體實現:
? ? 1、 首先創建一個繼承于UIButton的類(圓形帶數字的紅色UIButton),然后通過重載將父視圖的View傳過來。
- (instancetype)initWithFrame:(CGRect)frame withSuperView:(UIView *)badgeSuperView{
? ? ? ?if (self == [super initWithFrame:frame]) {
? ? ? ? ? ? ? ?self.bageValueSuperView = badgeSuperView;
? ? ? ? ? ? ? ? [self setup];
? ? ? ? ? }
? ? ? ? ? ? ? ? ?return self;
}
2、設置圓形帶數字的紅色UIButton的相關屬性,然后為這個按鈕添加上UIPanGestureRecognizer拖動手勢。另外還要創建形變效果圖的尾端的另一個紅色的圓形UIView對象以及相關屬性。這一步實際就是上面的[self setup];方法的實現。
3、接下來看一下拖動手勢中的代碼。相關注釋在代碼中
- (void)pan:(UIPanGestureRecognizer *)pan{
? ? ? ? ? CGPoint tranP = [pan translationInView:self];
? ? ? ? ? CGPoint center = self.center;
? ? ? ? ? ?center.x += tranP.x;
? ? ? ? ? ?center.y += tranP.y;
? ? ? ? ? ?self.center = center;
? ? ? ? ? ? [pan setTranslation:CGPointZero inView:self];?
? ? ? ? ? ? //這個方法主要是計算圓形UIButton和圓形UIView的中心點之間的距離
? ? ? ? ? ?CGFloat distance = [self distanceWithSmallCicle:self.smallCircle bigCircle:self];
? ? ? ? ? //這里設置小圓半徑隨著距離拉大而縮小
? ? ? ? ? CGFloat radius = self.bounds.size.width * 0.5;
? ? ? ? ? ?radius -= distance/10.0;
? ? ? ? ? self.smallCircle.bounds = CGRectMake(0, 0, radius * 2, radius * 2);
? ? ? ? ? self.smallCircle.layer.cornerRadius = radius;
/*******************路徑轉為形狀******************************/
? ? ? ? if (self.smallCircle.hidden == NO) {
? ? ? ? ? ? ? ? //這里是計算形變路徑關鍵的六個點,然后返回一個路徑的方法,具體計算下面會有圖解。把路徑轉換成圖形shapeLayer可以根據路徑生成形狀。shapeLayer是CAShapeLayer的實例對象。
? ? ? ? ? ? ? ? ? ? UIBezierPath *path = [self pathWithSmallCircle:self.smallCircle bigCircle:self];
? ? ? ? ? ? ? ? ? ?self.shapeLayer.path = path.CGPath;
? ? ? ? ? ? ? ? ? ? [self.bageValueSuperView.layer insertSublayer:_shapeLayer atIndex:0];
? ? ? ? ?}
/**********************關鍵業務邏輯處理*****************************/
? ? ? ? ? ? ? //拖動距離大于60的話就隱藏形變路徑和紅色UIView
? ? ? ? ? ?if (distance > 60) {
? ? ? ? ? ? ? ? ? ?self.smallCircle.hidden = YES;
? ? ? ? ? ? ? ? ? [self.shapeLayer removeFromSuperlayer]; ? ??
? ? ? ? ? ?}
//拖動結束,距離大于60就隱藏所有控件,展示爆炸動畫。小于60就展示原本的狀態
? ? ? ? ? if (pan.state == UIGestureRecognizerStateEnded) {
? ? ? ? ? ? ? ? ? ? if (distance < 60) {
? ? ? ? ? ? ? ? ? ? ? ? ? self.center = self.smallCircle.center;
? ? ? ? ? ? ? ? ? ? ? ? ?self.smallCircle.hidden = NO;
? ? ? ? ? ? ? ? ? ? ? ? ? [self.shapeLayer removeFromSuperlayer];
? ? ? ? ? ? ? ? ? ? ?}else{
? ? ? ? ? ? ? ? ? ? ? ? ? ?//播放一個動畫,動畫執行完畢,移除所有控件。
? ? ? ? ? ? ? ? ? ? ? ? ? //動畫代碼這里省略,具體可以下載源代碼。源代碼下載鏈接在最上方
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ?}
}
? ? ?4.這里就主要來剖析一下,形變區域的相關計算問題。
? ? ? 繪制紅色形變區域關鍵的一步是計算出圖中A、B、C、D、O、P四個點的位置,其中O和P點分別為AD何BC曲線的控制點。計算出六個點的位置后,便可通過貝塞爾曲線連接六個點,最后關閉路徑、添加填充,便可形成一個封閉圖形。六個點的具體計算是通過勾股定理計算,計算六個點的坐標,圖中的輔助線很重要。根據輔助線我們不難發現凡是圖中標記為Θ的角度,他們的值都相等。通過兩個圓的圓心位置,不難計算出Θ值。根據Θ值以及圓心位置,便可輕而易舉的計算出A、B、C、D四個點的值。另外還需要注意的是,OP的連線垂直于兩個圓心所在的直線,且OA和BP的長度為兩個圓心距離的一半,進而根據OA和BP外加圖中的虛線輔助線,可分別計算出O點和P點圓心所在的位置。最后便可形成一個封閉區域。說了這么多,接下來可以下載一下源代碼研究下。鏈接見上方????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????v????????????????????????????????新年快樂!!!!!