標籤:android 拖拽 紅點 qq
新版手機QQ5.+上新增了一種“一鍵退朝”的功能,即在頁面上的紅點可進行拖拽消除。在[知乎](http://www.zhihu.com/question/26382740)上可參考紅點的設計過程。按照設計思路在Android上模仿手Q實現下拖拽的過程。
代碼地址:https://github.com/chenupt/BezierDemo
:
整體的思路,封裝好一個view。在介面上找到四個點,即框出手勢拖動點與紅點之間的範圍,利用貝茲路徑修飾邊框,計算紅點和手勢拖動點間的距離,判斷紅點的消除與回彈。
借用下設計圖:
首先確定以紅點為座標原點,在座標上所要計算的就是p1, p2, p3, p4四個點,其中..為貝茲路徑,在p1p2和p3p4之間需要繪製半徑為R和r的圓。
接下來需要的就是在拖動過程中計算(0,0)和(x0, y0)兩點間的距離,通過距離控制貝茲路徑的弧度和圓的大小,實現類比現實生活中彈性效果。
在代碼中通過Path來控制p1, p2, p3, p4四個點所圍成的範圍,並填充相應地色值:
1.確定四個點,這裡簡單地將兩個圓起始半徑設定相等
float x1 = startX - offsetX; float y1 = startY + offsetY; float x2 = x - offsetX; float y2 = y + offsetY; float x3 = x + offsetX; float y3 = y - offsetY; float x4 = startX + offsetX; float y4 = startY - offsetY; path.reset(); path.moveTo(x1, y1); path.quadTo(anchorX, anchorY, x2, y2); path.lineTo(x3, y3); path.quadTo(anchorX, anchorY, x4, y4); path.lineTo(x1, y1);
2.填充範圍和繪製圓形:
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY);canvas.drawPath(path, paint);canvas.drawCircle(startX, startY, radius, paint);canvas.drawCircle(x, y, radius, paint);
3.在調用super.onDraw(canvas);方法繪製在canvas層上面的訊息點表徵圖imageView
通過在代碼中的onTouchEvent方法進行控制觸摸點的相應位置,實現拖動的效果。
@Override public boolean onTouchEvent(MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_DOWN){ // 判斷觸摸點是否在tipImageView中 Rect rect = new Rect(); int[] location = new int[2]; tipImageView.getDrawingRect(rect); tipImageView.getLocationOnScreen(location); rect.left = location[0]; rect.top = location[1]; rect.right = rect.right + location[0]; rect.bottom = rect.bottom + location[1]; if (rect.contains((int)event.getRawX(), (int)event.getRawY())){ isTouch = true; } }else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){ isTouch = false; tipImageView.setX(startX - tipImageView.getWidth()/2); tipImageView.setY(startY - tipImageView.getHeight()/2); } invalidate(); if(isAnimStart){ return super.onTouchEvent(event); } anchorX = (event.getX() + startX)/2; anchorY = (event.getY() + startY)/2; x = event.getX(); y = event.getY(); return true; }
4.拖動過程中計算兩個圓心之間的距離,通過圓心間的距離調整圓心為(0, 0)圓的半徑大小
float distance = (float) Math.sqrt(Math.pow(y-startY, 2) + Math.pow(x-startX, 2));radius = -distance/15+DEFAULT_RADIUS;
用新的半徑去繪製(0, 0)的圓,這樣隨著距離的增加,圓相應變小就給人如同快要沾不住黏黏的感覺。
5.距離超過設定的最大範圍,則設定為紅點掙脫狀態,如果手指抬起,則開始播放相應爆炸動畫。
exploredImageView.setVisibility(View.VISIBLE);exploredImageView.setImageResource(R.drawable.tip_anim);((AnimationDrawable) exploredImageView.getDrawable()).stop();((AnimationDrawable) exploredImageView.getDrawable()).start();
6.在Activity布局中引用相應封裝好的view即可。
<github.chenupt.bezier.BezierView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" />
最開始設想的view在類似於紅點範圍的一個控制項,但是這樣實現就達不到拖動到父類控制項的範圍之外,比如拖動紅點超過頁簽布局範圍時,紅點則無法繪製。因此在QQ的訊息列表中是將其設定相應全屏的一個view。背景為的上個背景,這樣在最上一層實則只有紅點的控制項。這樣就能相應地拖動紅點到螢幕的各個位置。所以才會在紅點列表爆照動畫結束之前頁簽是不可點擊,並且拖動紅點的時候列表資料沒有重新整理。
也許是還有更好地實現方式,歡迎大家進行交流。
代碼地址:https://github.com/chenupt/BezierDemo
QQ:753785666
Email:[email protected]
手機QQ5.0紅點拖拽消除的實現