Android未讀消息拖動氣泡示例代碼詳解(附源碼)
前言
拖動清除未讀消息可以說在很多應(yīng)用中都很常見,也被用戶廣泛接受。本文是一個可以供參考的Demo,希望能有幫助。
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
最終效果圖及思路
實現(xiàn)關(guān)鍵:
氣泡中間的兩條邊,分別是以ab,cd為數(shù)據(jù)點,G為控制點的貝塞爾曲線。
步驟:
繪制圓背景以及文本;連接情況繪制貝塞爾曲線;另外端點繪制一個圓
關(guān)鍵代碼
1.定義,初始化等
狀態(tài):靜止、連接、分離、消失
在onSizeChanged中初始化狀態(tài),固定氣泡以及可動氣泡的圓心
代碼如下(示例):
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); init(w, h); } private void init(int w, int h) { mBubbleState = BUBBLE_STATE_DEFAULT; //設(shè)置固定氣泡圓心初始坐標(biāo) if (mBubFixedCenter == null) { mBubFixedCenter = new PointF(w / 2, h / 2); } else { mBubFixedCenter.set(w / 2, h / 2); } //設(shè)置可動氣泡圓心初始坐標(biāo) if (mBubMovableCenter == null) { mBubMovableCenter = new PointF(w / 2, h / 2); } else { mBubMovableCenter.set(w / 2, h / 2); } }
2.onDraw中繪制包括三樣繪制
第一樣:靜止,連接,分離狀態(tài)都需要繪制圓背景以及文本:
//靜止,連接,分離狀態(tài)都需要繪制圓背景以及文本 if (mBubbleState != BUBBLE_STATE_DISMISS) { canvas.drawCircle(mBubMovableCenter.x, mBubMovableCenter.y, mBubMovableRadius, mBubblePaint); mTextPaint.getTextBounds(mTextStr, 0, mTextStr.length(), mTextRect); canvas.drawText(mTextStr, mBubMovableCenter.x - mTextRect.width() / 2, mBubMovableCenter.y + mTextRect.height() / 2, mTextPaint); }
第二樣:連接狀態(tài)繪制貝塞爾曲線①。
if (mBubbleState == BUBBLE_STATE_CONNECT) { //繪制靜止的氣泡 canvas.drawCircle(mBubFixedCenter.x, mBubFixedCenter.y, mBubFixedRadius, mBubblePaint); //計算控制點的坐標(biāo) int iAnchorX = (int) ((mBubMovableCenter.x + mBubFixedCenter.x) / 2); int iAnchorY = (int) ((mBubMovableCenter.y + mBubFixedCenter.y) / 2); float sinTheta = (mBubMovableCenter.y - mBubFixedCenter.y) / mDist; float cosTheta = (mBubMovableCenter.x - mBubFixedCenter.x) / mDist; //D float iBubFixedStartX = mBubFixedCenter.x - mBubFixedRadius * sinTheta; float iBubFixedStartY = mBubFixedCenter.y + mBubFixedRadius * cosTheta; //C float iBubMovableEndX = mBubMovableCenter.x - mBubMovableRadius * sinTheta; float iBubMovableEndY = mBubMovableCenter.y + mBubMovableRadius * cosTheta; //A float iBubFixedEndX = mBubFixedCenter.x + mBubFixedRadius * sinTheta; float iBubFixedEndY = mBubFixedCenter.y - mBubFixedRadius * cosTheta; //B float iBubMovableStartX = mBubMovableCenter.x + mBubMovableRadius * sinTheta; float iBubMovableStartY = mBubMovableCenter.y - mBubMovableRadius * cosTheta; mBezierPath.reset(); mBezierPath.moveTo(iBubFixedStartX, iBubFixedStartY); mBezierPath.quadTo(iAnchorX, iAnchorY, iBubMovableEndX, iBubMovableEndY); mBezierPath.lineTo(iBubMovableStartX, iBubMovableStartY); mBezierPath.quadTo(iAnchorX, iAnchorY, iBubFixedEndX, iBubFixedEndY); mBezierPath.close(); canvas.drawPath(mBezierPath, mBubblePaint); }
第三樣:消失狀態(tài)執(zhí)行爆炸動畫
// 認(rèn)為是消失狀態(tài),執(zhí)行爆炸動畫 if (mBubbleState == BUBBLE_STATE_DISMISS && mCurDrawableIndex < mBurstBitmapsArray.length) { mBurstRect.set( (int) (mBubMovableCenter.x - mBubMovableRadius), (int) (mBubMovableCenter.y - mBubMovableRadius), (int) (mBubMovableCenter.x + mBubMovableRadius), (int) (mBubMovableCenter.y + mBubMovableRadius)); canvas.drawBitmap(mBurstBitmapsArray[mCurDrawableIndex], null, mBurstRect, mBubblePaint); }
3.onTouchEvent中
按下:區(qū)分靜止?fàn)顟B(tài)和連接狀態(tài)
case MotionEvent.ACTION_DOWN: if (mBubbleState != BUBBLE_STATE_DISMISS) { mDist = (float) Math.hypot(event.getX() - mBubFixedCenter.x, event.getY() - mBubFixedCenter.y); if (mDist < mBubbleRadius + MOVE_OFFSET) { //加上MOVE_OFFSET是為了方便拖拽 mBubbleState = BUBBLE_STATE_CONNECT; } else { mBubbleState = BUBBLE_STATE_DEFAULT; } } break;
移動:判斷是否到了分離狀態(tài)
case MotionEvent.ACTION_MOVE: if (mBubbleState != BUBBLE_STATE_DEFAULT) { mDist = (float) Math.hypot(event.getX() - mBubFixedCenter.x, event.getY() - mBubFixedCenter.y); mBubMovableCenter.x = event.getX(); mBubMovableCenter.y = event.getY(); if (mBubbleState == BUBBLE_STATE_CONNECT) { if (mDist < mMaxDist - MOVE_OFFSET) { mBubFixedRadius = mBubbleRadius - mDist / 8; } else { mBubbleState = BUBBLE_STATE_APART; } } invalidate(); } break;
彈起:判斷是否已經(jīng)到了分離狀態(tài),分離狀態(tài)爆炸,未分離反彈
case MotionEvent.ACTION_UP: if (mBubbleState == BUBBLE_STATE_CONNECT) { // 橡皮筋動畫 startBubbleRestAnim(); } else if (mBubbleState == BUBBLE_STATE_APART) { if (mDist < 2 * mBubbleRadius){ //反彈動畫 startBubbleRestAnim(); }else{ // 爆炸動畫 startBubbleBurstAnim(); } } break;
4.反彈和爆炸動畫
/** * 連接狀態(tài)下松開手指,執(zhí)行類似橡皮筋動畫 */ private void startBubbleRestAnim() { ValueAnimator anim = ValueAnimator.ofObject(new PointFEvaluator(), new PointF(mBubMovableCenter.x, mBubMovableCenter.y), new PointF(mBubFixedCenter.x, mBubFixedCenter.y)); anim.setDuration(200); anim.setInterpolator(new OvershootInterpolator(5f)); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mBubMovableCenter = (PointF) animation.getAnimatedValue(); invalidate(); } }); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); mBubbleState = BUBBLE_STATE_DEFAULT; } }); anim.start(); }
/** * 爆炸動畫 */ private void startBubbleBurstAnim() { //將氣泡改成消失狀態(tài) mBubbleState = BUBBLE_STATE_DISMISS; ValueAnimator animator = ValueAnimator.ofInt(0, mBurstBitmapsArray.length); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(500); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCurDrawableIndex = (int) animation.getAnimatedValue(); invalidate(); } }); animator.start(); }
總結(jié)
注:①貝塞爾曲線參考博文
本文完,有需要參考的同學(xué)→文中Demo下載地址
本系列文章引導(dǎo)頁點擊這里
到此這篇關(guān)于Android未讀消息拖動氣泡示例代碼詳解的文章就介紹到這了,更多相關(guān)Android未讀消息拖動氣泡內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 不同Activity間數(shù)據(jù)的傳遞 Bundle對象的應(yīng)用
本篇文章小編為大家介紹,Android 不同Activity間數(shù)據(jù)的傳遞 Bundle對象的應(yīng)用。需要的朋友參考下2013-04-04Android UI自定義ListView實現(xiàn)下拉刷新和加載更多效果
這篇文章主要介紹了Android UI自定義ListView實現(xiàn)下拉刷新和加載更多效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11Android實現(xiàn)跟隨手指拖動并自動貼邊的View樣式(實例demo)
本文通過實例代碼給大家介紹了android實現(xiàn)跟隨手指拖動并自動貼邊的View樣式,效果非常棒,具有參考借鑒價值,需要的朋友參考下吧2017-01-01Android Jetpack架構(gòu)組件Lifecycle詳解
這篇文章主要介紹了Android Jetpack架構(gòu)組件Lifecycle詳解,Lifecycle是Jetpack架構(gòu)組件中用來感知生命周期的組件,使用Lifecycles可以幫助我們寫出和生命周期相關(guān)更簡潔更易維護的代碼。對此感興趣的小伙伴可以來學(xué)習(xí)一下2020-07-07