QQ 未讀消息的拖拽動態效果是如何實現的?
不知道題主問的是不是這個東西??
如果是的話,我可以解釋一下,這個效果就是貝塞爾曲線的一種應用,這裡我就用安卓代碼實現一下。
我們把這個東西的效果拆解一下
A,B是兩個圓形,AB之間是一個由abcd四條path圍成的動態的C區域,其中bd兩條貝塞爾曲線有公有控制點e,e是ac圓心之差/2;
核心邏輯:一開始的時候 ,A,B的圓心是重合的,隨著A,B距離增加,A的直徑變小,帶來C區域視覺上的拉長,到達一定距離後,B隨著一段幀動畫消失,A的直徑變為0消失;
首先,自定義一個View後,建立核心參數:
第一步:計算獲得兩個圓心之間的動態距離distance,並通過距離來控制A圓的大小;
第二步:求取貝塞爾曲線控制點e的動態坐標與1,2,3,4四點動態坐標:
1、獲得A,B圓之間的偏移量
2、有了偏移量就可以求出圓心兩點斜率了
有了斜率,圓心坐標和直徑,就可以通過計算獲得1,2,3,4 四個點的動態實時坐標;
第三步:現在核心參數都已經計算獲得,就可以用畫筆畫出中間C圖形的path了,path由3→4→2→1順序畫出;
第四步:所有部件都準備好,現在只要寫出onTouchEvent中的邏輯;
1、ACTION_DOWN按下時
2,ACTION_MOVE手指移動時
3,ACTION_CANCEL抬起手指時
OK。完成,運行一下看看效果
完成
源碼我放在百度雲盤了,
說實話,像這種漂亮的小控制項,做出來不是很難,難的是創意,想出這個idea的設計師才是寶貝
-- 1月10日更
第一次回答破千贊,謝謝大家(,,?? . ??,,)
QQ手機版 5.0「一鍵下班」設計小結
如果是想問怎麼繪製出小紅點被拉長的效果,其實祥子已經解釋的很清楚了。不過光明白這點,你並不能完成一個能夠拿來用的小紅點組件。
因為祥子沒有提到一個核心問題就是,如何解決在超出View 觸摸響應範圍繼續拖動小紅點。
我看了下源碼,加了個黑色背景色來區分。發現自定的View寬高都很大,其實這樣是沒有意義的,因為小紅點只能在自身的View範圍內拖動,如下圖,當超過邊界的時候,已經不會顯示了。(提一個bug,源碼裡面的點擊黑色區域內任意位置,都會導致觸發小紅點拖動效果。)
而且實際開發中,自定義View可能會需要全屏可拖動,且一般只要自定義View寬高剛好包含繪製的小紅點即可,不然會擠占其它View的位置。(下面的小紅點自定義View我稱為DotView。)
下圖是祥子代碼演示的截圖,可以看到超過邊界後已經不能顯示了(我只改了下自定義View的背景色,方便區分)
不過,很久前我也默默的實現過這個可拖動小紅點的功能。(源碼見Github:lsxiao/DraggableDot)
我解決全屏拖動的做法是借鑒了一個很老的叫做SlidingMenu的開源庫,(SlidingMenu 源碼解析 @codeKK 開源站)。
由於在Activity 的Content View之上還有DecorView:
所以我們是不是可以在我們DecorView和Activity Content View之間再加上一層DraggableLayout來做觸摸事件檢測和拖動效果繪製(除掉status bar和navigation bar之外)
這樣我們就可以實現應用內非侵入式的全屏小紅點觸摸檢測和全屏可拖動動效繪製。
(實際上插入DraggableLayout後的視圖層次要比下圖複雜,下圖做了簡化,道理是一樣的)
只要知道小紅點相對於屏幕的位置,我們就可以在DraggeableLayout層進行觸摸事件攔截的時候進行識別是否觸摸到了小紅點,是否在觸摸到小紅點後有拖動動作,等等。
之後根據相應的動作在DraggeableLayout層繪製小紅點被拖動的每一幀即可(別忘記了在繪製的時候將DotView隱藏掉,不然會有一個沒有動作改變的小紅點顯示在原來的位置),即實現拖動效果。
當然,如果沒有觸摸到小紅點,我們則對觸摸事件進行放行。
也就是說,DotView只是作為一個佔位功能,實際上我們對它的操作無非顯示和隱藏。
目的是為了讓DraggeLayout能根據小紅點位置測算初始的觸摸範圍,和標記拖動開始的初始位置,真實觸摸檢測和拖動效果的繪製在DraggableLayout里進行,由於DraggableLayout在Content View之上,所以做到了全屏覆蓋的效果。
核心代碼如下:
/*if is exist,don"t attachToActivity again*/ /**
* attachToActivity draggableLayout to view tree and make draggableLayout be a child of the decorView,
* then let the content view become a child of the draggableLayout.
* &
* Draggable dot and the animation will draw on draggable layer which will be drew above on it"s children,
* the DotView is just a placeHolder to listen the down event and notify DraggableLayout to handle the draggable events.
* so,the DotView can be used in any layout,it"s won"t have any influence on your own layout.
*
* @param activity Activity
*/
public static void attachToActivity(Activity activity) {
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
for (int i = 0; i &< decorView.getChildCount(); i++) {
View view = decorView.getChildAt(i);
if (view instanceof DraggableLayout) {
return;
}
}
/*not exist, need to attachToActivity draggableLayout to view tree*/
DraggableLayout draggableLayout = new DraggableLayout(activity);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
draggableLayout.setLayoutParams(params);
for (int i = 0; i &< decorView.getChildCount(); i++) {
View v = decorView.getChildAt(i);
decorView.removeView(v);
draggableLayout.addView(v);
}
decorView.addView(draggableLayout, 0);
}
QQ手機版 5.0「一鍵下班」設計小結
iOS實現的github地址:https://github.com/wzpziyi1/QQ-Goo
附個IOS的實現~
wufeifan890330/DragBubbleView
svg 融球效果
其實挺容易 來個android版本的實現 https://github.com/siwangqishiq/DragIndicatorView
粘性控制項?
推薦閱讀: