国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的示例

瀏覽:107日期:2022-06-06 08:00:29
效果圖:

Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的示例

一、實(shí)現(xiàn)思路

在列表中默認(rèn)使用自定義的TextView控件來(lái)展示消息氣泡,在自定義的TextView控件中重寫(xiě)onTouchEvent方法,然后在DOWN、MOVE、UP事件中分別處理拖拽效果。

整個(gè)拖拽效果我們可以拆分成以下幾步來(lái)實(shí)現(xiàn):1.默認(rèn)狀態(tài)2.兩氣泡相連狀態(tài)3.兩氣泡分離狀態(tài)4.氣泡消失狀態(tài)

二、功能實(shí)現(xiàn)

默認(rèn)狀態(tài):用來(lái)做一個(gè)狀態(tài)的標(biāo)識(shí),無(wú)需特別處理。

兩氣泡相連狀態(tài):繪制一個(gè)固定圓和一個(gè)移動(dòng)圓,使用兩條貝塞爾曲線來(lái)實(shí)現(xiàn)兩氣泡連接的曲線,兩條貝塞爾曲線共用同一個(gè)控制點(diǎn),然后根據(jù)MOVE事件中的坐標(biāo)不斷重繪移動(dòng)圓。

實(shí)現(xiàn)兩氣泡連接的效果,需要先計(jì)算出一些點(diǎn)的坐標(biāo),這也是整個(gè)拖拽氣泡效果的核心部分,具體如下圖:

Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的示例

如圖,A點(diǎn)到B點(diǎn)是一條二階貝塞爾曲線,C點(diǎn)到D點(diǎn)也是一條二階貝塞爾曲線,它們共用同一個(gè)控制點(diǎn),所以我們要計(jì)算出A點(diǎn)、B點(diǎn)、C點(diǎn)、D點(diǎn)以及控制點(diǎn)的坐標(biāo)。

首先來(lái)計(jì)算控制點(diǎn)的坐標(biāo),控制點(diǎn)的坐標(biāo)和容易計(jì)算出,也就是固定圓的x坐標(biāo)加上移動(dòng)圓的x坐標(biāo),再除以2,固定圓的y坐標(biāo)同理得出。

int controlX = (int) ((mBubStillCenter.x + mBubMoveCenter.x) / 2);int controlY = (int) ((mBubStillCenter.y + mBubMoveCenter.y) / 2);

根據(jù)圖中所標(biāo)注的信息得知,∠a=∠d,∠b=∠c,∠a=∠θ,由此可知,我們求出∠θ所在的直角三角形的sin和cos值,就可以計(jì)算出A點(diǎn)、B點(diǎn)、C點(diǎn)、D點(diǎn)的坐標(biāo)。

sin值可以通過(guò)移動(dòng)圓的y坐標(biāo)減去固定圓的y坐標(biāo),再除以兩圓心的距離,也就是O1到O2的距離。

cos值可以通過(guò)移動(dòng)圓的x坐標(biāo)減去固定圓的x坐標(biāo),再除以兩圓心的距離。

float sin = (mBubMoveCenter.y - mBubStillCenter.y) / mDist;float cos = (mBubMoveCenter.x - mBubStillCenter.x) / mDist;

有了sin和cos值,對(duì)應(yīng)的A點(diǎn)、B點(diǎn)、C點(diǎn)、D點(diǎn)的坐標(biāo)就好計(jì)算了

// A點(diǎn)float bubbleStillStartX = mBubStillCenter.x + mBubbleStillRadius * sin;float bubbleStillStartY = mBubStillCenter.y - mBubbleStillRadius * cos;// B點(diǎn)float bubbleMoveStartX = mBubMoveCenter.x + mBubbleMoveRadius * sin;float bubbleMoveStartY = mBubMoveCenter.y - mBubbleMoveRadius * cos;// C點(diǎn)float bubbleMoveEndX = mBubMoveCenter.x - mBubbleMoveRadius * sin;float bubbleMoveEndY = mBubMoveCenter.y + mBubbleMoveRadius * cos;// D點(diǎn)float bubbleStillEndX = mBubStillCenter.x - mBubbleStillRadius * sin;float bubbleStillEndY = mBubStillCenter.y + mBubbleStillRadius * cos;

接下來(lái)就是把這些貝塞爾曲線和直線連起來(lái),就實(shí)現(xiàn)了兩氣泡相連的效果。

兩氣泡分離狀態(tài):當(dāng)拖拽的移動(dòng)圓超出固定圓一定范圍時(shí),就進(jìn)入了兩氣泡分離狀態(tài),此時(shí)我們只需要繪制移動(dòng)圓即可。當(dāng)拖拽的移動(dòng)圓回到固定圓一定范圍時(shí),此時(shí)會(huì)進(jìn)入兩氣泡相連狀態(tài),并且需要實(shí)現(xiàn)一個(gè)氣泡還原的效果。(這里會(huì)有個(gè)難點(diǎn),就是移動(dòng)圓我們可以在屏幕上任意拖動(dòng)而不被遮擋,這里放到后面來(lái)實(shí)現(xiàn)。)

public void move(float curX, float curY) { mBubMoveCenter.x = curX; mBubMoveCenter.y = curY; mDist = (float) Math.hypot(curX - mBubStillCenter.x, curY - mBubStillCenter.y); if(mBubbleState == BUBBLE_STATE_CONNECT){ if(mDist < mMaxDist - MOVE_OFFSET){ mBubbleStillRadius = mBubbleRadius - mDist / 10; }else { mBubbleState = BUBBLE_STATE_APART; } } invalidate();}

mDist就是兩圓心的距離。

/** * 氣泡還原動(dòng)畫(huà) */private void startBubbleRestAnim() { mBubbleStillRadius = mBubbleRadius; ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), new PointF(mBubMoveCenter.x, mBubMoveCenter.y), new PointF(mBubStillCenter.x, mBubStillCenter.y)); animator.setDuration(200); animator.setInterpolator(input -> { float factor = 0.4f; return (float) (Math.pow(2, -10 * factor) * Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1); }); animator.addUpdateListener(animation -> { mBubMoveCenter = (PointF) animation.getAnimatedValue(); invalidate(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mBubbleState = BUBBLE_STATE_DEFAULT; removeDragView(); if(mDragListener != null){mDragListener.onRestore(); } } }); animator.start();}

分享一個(gè)可視化插值器的網(wǎng)站,其中內(nèi)置了一些插值器公式,還可以查看動(dòng)畫(huà)演示效果。http://inloop.github.io/interpolator/

氣泡消失狀態(tài):當(dāng)拖拽的移動(dòng)圓超出一定范圍時(shí),并且松開(kāi)了手指后,此時(shí)進(jìn)入氣泡消失狀態(tài),此時(shí)我們需要實(shí)現(xiàn)一個(gè)爆炸的動(dòng)畫(huà)。

爆炸的動(dòng)畫(huà)通過(guò)繪制一組圖片來(lái)實(shí)現(xiàn)

if(mBubbleState == BUBBLE_STATE_DISMISS){ if(mIsBurstAnimStart){ mBurstRect.set((int)(mBubMoveCenter.x - mBubbleMoveRadius), (int)(mBubMoveCenter.y - mBubbleMoveRadius),(int)(mBubMoveCenter.x + mBubbleMoveRadius), (int)(mBubMoveCenter.y + mBubbleMoveRadius)); canvas.drawBitmap(mBurstBitmapArray[mCurDrawableIndex], null, mBurstRect, mBurstPaint); }}

mCurDrawableIndex是圖片的索引,是通過(guò)屬性動(dòng)畫(huà)來(lái)改變

/** * 氣泡爆炸動(dòng)畫(huà) */private void startBubbleBurstAnim() { ValueAnimator animator = ValueAnimator.ofInt(0, mBurstDrawablesArray.length); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(1000); animator.addUpdateListener(animation -> { mCurDrawableIndex = (int) animator.getAnimatedValue(); invalidate(); }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mIsBurstAnimStart = false; if(mDragListener != null){mDragListener.onDismiss(); } } }); animator.start();}三、全屏拖拽效果實(shí)現(xiàn)

首先在DOWN事件中獲取當(dāng)前觸摸位置在全屏所在位置,然后將當(dāng)前view緩存為bitmap,并把此bitmap添加到rootview中,拖動(dòng)的時(shí)候直接繪制此bitmap。

//獲得當(dāng)前View在屏幕上的位置int[] cLocation = new int[2];getLocationOnScreen(cLocation);if(rootView instanceof ViewGroup){ mDragDotView = new DragDotView(getContext()); //設(shè)置固定圓和移動(dòng)圓的圓心坐標(biāo) mDragDotView.setDragPoint(cLocation[0] + mWidth / 2, cLocation[1] + mHeight / 2, mRawX, mRawY); Bitmap bitmap = getBitmapFromView(this); if(bitmap != null){ mDragDotView.setCacheBitmap(bitmap); ((ViewGroup) rootView).addView(mDragDotView); setVisibility(INVISIBLE); }}/** * 將當(dāng)前view緩存為bitmap,拖動(dòng)的時(shí)候直接繪制此bitmap * @param view * @return */public Bitmap getBitmapFromView(View view){ Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap;}

至此,整個(gè)消息氣泡拖拽效果的核心部分就實(shí)現(xiàn)了

源碼地址:

https://github.com/loren325/CustomerView

以上就是Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的示例的詳細(xì)內(nèi)容,更多關(guān)于Android 實(shí)現(xiàn)仿QQ拖拽氣泡效果的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: qq
相關(guān)文章:
主站蜘蛛池模板: 亚洲免费成人网 | 久久在线资源 | 国产精品1区2区 | 九九99香蕉在线视频免费 | 国产精品久久久久久久久久久威 | 99久久久国产精品免费播放器 | 失禁h啪肉尿出来高h男男 | 亚洲男人天 | 8050网午夜一级毛片免费不卡 | 九色福利| 在线亚洲日产一区二区 | 欧美日韩视频一区二区在线观看 | 久久精品国产99国产精品 | 亚洲国产欧美在线人成精品一区二区 | 成人黄色免费看 | 一级毛毛片毛片毛片毛片在线看 | 成人毛片免费免费 | 欧美视频在线一区二区三区 | 国产精品高清免费网站 | 国内精品久久久久久中文字幕 | a级国产乱理伦片在线观看国 | 黄色毛片视频在线观看 | 操美女大逼视频 | 亚洲国产情侣一区二区三区 | 韩国精品一区二区三区四区五区 | 国产精品视频久 | 性色xxx | 欧美综合自拍亚洲综合百度 | 欧美做暖小视频xo免费 | 亚洲第一区视频 | 国内成人精品视频 | 免费在线黄色网址 | 国产一级做a爱片久久毛片a | 欧美a在线看 | a级片一级片 | 成人网视频在线观看免费 | 一区二区三区免费视频 www | 99久久精品视香蕉蕉er热资源 | 免费观看欧美成人h | 在线另类视频 | 性夜黄a爽爽免费视频国产 性夜影院爽黄a爽免费看网站 |