亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統(tǒng) > Android > 正文

Android使用ViewDragHelper實現(xiàn)QQ聊天氣泡拖動效果

2019-10-21 21:26:30
字體:
供稿:網(wǎng)友

QQ聊天氣泡拖動效果Android實現(xiàn)代碼,供大家參考,具體內(nèi)容如下

概述

Android,ViewDragHelper,QQ聊天,氣泡,拖動

本文的目的是實現(xiàn)類似于QQ消息提醒的氣泡的拖拽效果。網(wǎng)上已有大神的實現(xiàn)效果是通過監(jiān)聽控件的OnTouchEvent事件的ACTION_DOWN,ACTION_MOVE,ACTION_UP事件來處理相應(yīng)的拖拽效果,這里采用ViewDragHelper的方式去實現(xiàn)拖拽,順便學(xué)習(xí)了一下ViewDragHelper的使用方式,拖拽時的粘連效果采用貝塞爾曲線來實現(xiàn)。

用ViewDragHelper實現(xiàn)拖拽效果

ViewDragHelper是Google在v4的支持包中提供的一款用來解決界面控件拖拽移動問題的類,使用時首先要通過ViewDragHelper.create(ViewGroup forParent, float sensitivity, Callback cb)方法來獲取ViewDragHelper的實例對象,然后在需要支持拖拽的ViewGroup的onInterceptTouchEvent和onTouchEvent中添加代碼,最后我們需要寫一個類繼承ViewDragHelper.Callback,重寫其中的方法,就能實現(xiàn)拖拽效果了。

為了實現(xiàn)拖拽效果,我們首先需要寫一個類DragLayout繼承LinearLayout,在其中的控件都可以利用ViewDragHelper實現(xiàn)拖拽效果,在DragLayout的初始化方法中我們獲取一個ViewDragHelper的實例

/** * @params ViewGroup forParent 必須是一個ViewGroup * @params float sensitivity 靈敏度 * @params Callback cb 回調(diào) */mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragCallback());

三個參數(shù)中this就是當(dāng)前DragLayout類,sensitivity表示拖拽的靈敏度,一般用1.0f即可,第三個參數(shù)即為ViewDragHelper.Callback類型的拖拽回調(diào),我們在重寫回調(diào)中的函數(shù)就能實現(xiàn)拖拽效果,獲取到mDragHelper后我們需要在onInterceptTouchEvent和onTouchEvent中用mDragHelper控制屏幕的觸摸事件

@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) {  case MotionEvent.ACTION_CANCEL:  case MotionEvent.ACTION_DOWN:   mDragHelper.cancel(); // 相當(dāng)于調(diào)用 processTouchEvent收到ACTION_CANCEL   break; } /**  * 檢查是否可以攔截touch事件  * 如果onInterceptTouchEvent可以return true 則這里return true  */ return mDragHelper.shouldInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) { /**  * 處理攔截到的事件  * 這個方法會在返回前分發(fā)事件  */ mDragHelper.processTouchEvent(event); return true;}

接下來就要去寫一個類繼承ViewDragHelper.Callback來實現(xiàn)拖拽效果了

private class ViewDragCallback extends ViewDragHelper.Callback { /**  * 嘗試捕獲子view,一定要返回true  *  * @param view  嘗試捕獲的view  * @param pointerId 指示器id?  *     這里可以決定哪個子view可以拖動  */ @Override public boolean tryCaptureView(View view, int pointerId) {  if (view.getId() == R.id.tv_drag) {   return true;  } else {   return false;  } } /**  * 處理水平方向上的拖動  *  * @param child 被拖動到view  * @param left 移動到達的x軸的距離  * @param dx 建議的移動的x距離  */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) {  // 兩個if主要是為了讓viewViewGroup里  if (getPaddingLeft() > left) {   return getPaddingLeft();  }  if (getWidth() - child.getWidth() < left) {   return getWidth() - child.getWidth();  }  return left; } /**  * 處理豎直方向上的拖動  *  * @param child 被拖動到view  * @param top 移動到達的y軸的距離  * @param dy 建議的移動的y距離  */ @Override public int clampViewPositionVertical(View child, int top, int dy) {  // 兩個if主要是為了讓viewViewGroup里  if (getPaddingTop() > top) {   return getPaddingTop();  }  if (getHeight() - child.getHeight() < top) {   return getHeight() - child.getHeight();  }  return top; } /**  * 拖拽移動時觸發(fā)的監(jiān)聽函數(shù)  * @param changedView 觸發(fā)該函數(shù)的View  * @param left View左邊界坐標(biāo)  * @param top View上邊界坐標(biāo)  * @param dx 該次橫向移動坐標(biāo)  * @param dy 該次縱向移動坐標(biāo)  */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {   if (changedView.getId() == R.id.tv_drag) {   System.out.println("left = " + left + ", top = " + top + "dx = " + dx + ", dy = " + dy);   finalX = left;   finalY = top;   invalidate();  }  super.onViewPositionChanged(changedView, left, top, dx, dy); } /**  * 拖拽手指離開時回調(diào)  * @param releasedChild 拖拽的控件  * @param xvel 手指離開屏幕時拖拽控件的x方向的速度  * @param yvel 手指離開屏幕時拖拽控件的y方向的速度  */ @Override public void onViewReleased(View releasedChild, float xvel, float yvel) {  if (releasedChild == tvDot) {   if (getCenterDistance() < 300) { //連接線條未消失    mDragHelper.settleCapturedViewAt(dotOriX, dotOriY);    invalidate();   } else {    showBomb();   }  } }}

這里我們重寫了上述方法:

  • tryCaptureView返回true表示該控件可以拖拽。
  • 重寫clampViewPositionHorizontal,clampViewPositionVertical以防止控件拖拽出父控件的范圍,如果不需控制拖拽范圍可不設(shè)置。
  • onViewPositionChanged方法用于記錄拖拽時控件的坐標(biāo),onViewReleased方法用于在拖拽停止時進行相關(guān)操作。

在拖拽結(jié)束時我們判斷如果與初始距離小于300,則讓控件回到初始位置,如果大于三百則顯示氣泡爆炸動畫。小于300時調(diào)用

mDragHelper.settleCapturedViewAt(dotOriX, dotOriY);invalidate();

其中dotOriX,dotOriY是拖拽控件的原始位置,mDragHelper.settleCapturedViewAt(dotOriX, dotOriY)同時invalidate()刷新繪制后控件就會滾回原始位置,這里我們要注意重寫DragLayout的computeScroll才能有滾動回去的效果。

@Overridepublic void computeScroll() { if (mDragHelper.continueSettling(true)) {  invalidate(); }}

至此我們就實現(xiàn)了拖拽和滾回原始位置的效果。

粘連氣泡的實現(xiàn)

實現(xiàn)粘連氣泡需要在onDraw方法中畫出連接兩個小球的連線,同時需要根據(jù)滑動距離畫出一個逐漸縮小的原始小球。

在onDraw方法中實現(xiàn)相關(guān)功能前我們要注意,出于效率的考慮,ViewGroup 默認會繞過 onDraw() 方法,我們需要在其初始化時調(diào)用setWillNotDraw(false)方法來讓ViewGroup的onDraw方法執(zhí)行。

在布局開始的onLayout方法中我們獲取小球的大小和初始位置

dotOriX = tvDot.getLeft();dotOriY = tvDot.getTop();dotWidth = tvDot.getRight() - tvDot.getLeft();dotHeight = tvDot.getBottom() - tvDot.getTop();finalX = tvDot.getLeft();finalY = tvDot.getTop();

然后在ViewDragHelper.Callback的onViewPositionChanged回調(diào)中獲得拖拽的位置,畫出兩者之間的連線,由于大于一定距離時連線消失,我們需要一個變量showDragLine控制連線是否繪制。

@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); if (showDragLine) {  double distance = getCenterDistance();  int initRadius = (dotWidth / 2);  int finalRadius;  if (distance >= 300) {   finalRadius = 10;  } else {   finalRadius = ((300 - distance) * initRadius / 300) < 10 ? 10 : (int) ((300 - distance) * initRadius / 300);  }  if (distance < 300) {   drawOval(dotOriX + dotWidth / 2, dotOriY + dotHeight / 2, finalRadius, canvas);   Path path = drawAdhesionBody(dotOriX + dotWidth / 2, dotOriY + dotHeight / 2, finalRadius, 90f,     finalX + dotWidth / 2, finalY + dotHeight / 2, dotHeight / 2, 45f);   canvas.drawPath(path, mPaint);  } else {   showDragLine = false;  } }}

當(dāng)距離小于300時,drawOval方法在原始位置畫一個隨距離增大而變小的圓,同時獲取貝塞爾曲線的Path并且用drawAdhesionBody方法畫出,畫貝塞爾曲線原理圖如下

 

Android,ViewDragHelper,QQ聊天,氣泡,拖動

釋放時爆炸效果的實現(xiàn)

在釋放控件后判斷,如果釋放距離離原始距離大于閾值,就讓小球消失并且顯示爆炸動畫,由于爆炸的小球是不規(guī)則的動畫,所以只能通過gif的展示或者屬性動畫畫出一幀一幀圖片來實現(xiàn)動畫效果,這里我參考了仿qq消息氣泡拖拽,貝賽爾曲線的實現(xiàn),利用屬性動畫來實現(xiàn)該效果。

/** * 展示爆炸特效 */private void showBomb() { tvDot.setVisibility(GONE); mIsExplosionAnimStart = true; //做一個int型屬性動畫,從0開始,到氣泡爆炸圖片數(shù)組個數(shù)結(jié)束 ValueAnimator anim = ValueAnimator.ofInt(0, mExplosionDrawables.length); anim.setInterpolator(new LinearInterpolator()); anim.setDuration(500); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  @Override  public void onAnimationUpdate(ValueAnimator animation) {   //拿到當(dāng)前的值并重繪   mCurExplosionIndex = (int) animation.getAnimatedValue();   invalidate();  } }); anim.addListener(new AnimatorListenerAdapter() {  @Override  public void onAnimationEnd(Animator animation) {   //動畫結(jié)束后改變狀態(tài)   mIsExplosionAnimStart = false;  } }); anim.start();}

同時在onDraw方法中適時的繪制出爆炸效果

@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mIsExplosionAnimStart && mCurExplosionIndex < mExplosionDrawables.length) {  //設(shè)置氣泡爆炸圖片的位置  mExplosionRect.set((int) (finalX), (int) (finalY)    , (int) (finalX+dotWidth), (int) (finalY+dotHeight));  //根據(jù)當(dāng)前進行到爆炸氣泡的位置index來繪制爆炸氣泡bitmap  canvas.drawBitmap(mExplosionBitmaps[mCurExplosionIndex], null, mExplosionRect, mExplosionPaint); }}

總結(jié)

這個仿QQ氣泡拖拽效果只是實現(xiàn)了具體的效果,如果需要集成到項目中需要具體改動并封裝一些東西,另外在爆炸效果的處理上覺得應(yīng)該有比圖片屬性動畫更高效的繪制方式,只是限于個人水平所限暫時還未能想到。

項目地址:QQBubble

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
亚洲综合色区另类av| 午夜精品久久久久久毛片| 国产男女猛烈无遮挡免费视频| av在线天天| 日韩精品免费一区二区夜夜嗨| 菠萝菠萝蜜在线观看| 国产精品日本欧美一区二区三区| 亚洲www在线观看| 污污影院在线观看| 伊人222成人综合网| 99riav视频在线观看| 亚洲人免费短视频| 欧美无砖专区一中文字| 精品九九在线| 国产精品影片在线观看| 亚洲成人最新网站| 国产精品久久久久久久久免费| 欧美插插视频| 国产精品爱啪在线线免费观看| 又粗又黑又大的吊av| 亚洲综合久久久| 天堂中文在线看| 成人精品视频在线播放| 青青青国内视频在线观看软件| 精品成人av一区| 国产手机视频精品| 国产精品久久久久久亚洲影视| 国产一卡2卡3卡4卡网站免费| 精品一区二区三区久久| 韩国精品久久久| 福利视频大全| 视频三区在线观看| 在线免费av片| av免费一区二区| 天堂√中文最新版在线| 欧美亚洲国产怡红院影院| 影音先锋中文字幕在线观看| 九九精品视频在线看| 欧美久久精品一级c片| 99热这里只有成人精品国产| 国产一精品一av一免费爽爽| 日韩一区欧美小说| 精品国产视频一区二区三区| 91最新国产视频| 久久久一本二本三本| 亚洲毛片免费看| 国产黄色一级网站| 亚洲影视中文字幕| 深夜福利免费在线观看| 色偷偷一区二区三区| 激情小说亚洲色图| 你懂的视频在线观看| 日韩视频在线观看一区| 亚洲精品一区二区三区四区高清| 国产成人综合欧美精品久久| 韩国三级hd中文字幕| 色噜噜狠狠一区二区三区狼国成人| 欧美人与性动交a欧美精品| 成年女人18级毛片毛片免费| 美女网站视频黄色| 国产精品一二三区在线观看| 在线免费观看日本欧美| 91久久精品国产91性色tv| 日韩中文字幕亚洲一区二区va在线| 在线观看xxxx| 美女露胸一区二区三区| 亚洲激情成人| 成人动漫视频在线观看免费| 91黑人精品一区二区三区| 国产精品视频免费在线| 91社区视频在线观看| 少妇高潮爽到全身痉挛抽搐| 日本成年人网址| y97精品国产97久久久久久| 神马影院我不卡| 美女视频黄免费的久久| 日本免费在线观看视频| silk一区二区三区精品视频| 日韩精品一区二区三区免费观看| 亚洲欧洲综合网| 亚洲成人网久久久| 性chinese极品按摩| 国产免费视频一区二区三区| 日韩在线三区| 国产精品乱码久久久久| 精品国产乱码久久久久久1区2区| 欧美video巨大粗暴18| 国产乱子伦精品无码码专区| 国产女主播喷水视频在线观看| 国产精品熟女一区二区不卡| 欧美在线播放视频| 亚洲社区在线观看| 欧美大片一区二区| 国产色综合网| a在线观看视频| 欧美丝袜足交| 日本黄色小说视频| www.99久久热国产日韩欧美.com| 青青草一区二区| 精品国产免费一区二区三区四区| 亚洲天堂av一区| 伊人国产视频| 国产尤物91| 国产精品一区二区无线| 日韩中文字幕1| 亚洲欧美一区二区三区国产精品| 99热国产在线中文| 99国精产品一二二线| 国产精品国产三级国产aⅴ| 无码人妻精品一区二区蜜桃百度| 日韩一级免费毛片| 国产精品三区www17con| 少妇久久久久久被弄高潮| 成人福利片网站| 青青草原综合久久大伊人精品优势| 国产成人精品一区二区三区| 精品一区久久| 欧美aaaaaaaa| 日本欧洲一区二区| 韩国中文字幕av| 人人草在线观看| 宅男噜噜噜66国产日韩在线观看| 日本不卡不码高清免费观看| 图片一区二区| 婷婷色中文字幕| 少妇精品高潮欲妇又嫩中文字幕| 国产一区二区三区视频免费观看| 狠狠躁天天躁日日躁欧美| 欧美午夜国产| 99久久久精品免费观看国产蜜| 日本精品在线观看| 蜜桃传媒一区二区| 国产视频一视频二| 国模精品一区二区三区| 99爱视频在线| 天天干天天草天天| 青青草成人影院| 九九热国产在线| 亚洲国产欧美久久| 性欧美极品另类| 香蕉综合视频| 久蕉依人在线视频| 亚洲最新合集| 久热精品视频| 亚洲精品自拍视频在线观看| 色噜噜狠狠成人中文综合| 欧美一区二区三区精美影视| 69xxx免费| 韩国av一区二区三区四区| 国产精品视频最多的网站| 中文字幕v亚洲ⅴv天堂| 亚洲黄色免费电影| 日韩一区二区三区在线看| 日本三级黄色大片| 欧美成人性福生活免费看| 中文字幕色站| 激情视频极品美女日韩| 91在线观看地址| 久久www人成免费看片中文| 久久国产成人精品国产成人亚洲| 91在线视频一区| 欧美日韩蜜桃| 91九色在线免费视频| 亚洲国产天堂久久综合网| 国产精品福利一区二区三区| 91色中文字幕| 奇米影视四色在观看线| 成人免费淫片在线费观看| 日韩欧美一区视频| 欧美男体视频| 久久女同性恋中文字幕| 亚洲在线色站| 91官网在线免费观看| 婷婷在线播放| 亚洲电影一区二区| 99精品国产一区二区青青牛奶| 亚洲wwwav| 亚洲国产一区二区在线| 国产精品对白刺激久久久| 色噜噜国产精品视频一区二区| 忘忧草在线www成人影院| 日韩中文字幕一区二区三区| 中文字幕在线看精品乱码| 一区二区亚洲精品国产| 九一国产精品视频| 国产精品裸体瑜伽视频| 成人vr资源| 97超碰人人在线| 五月婷婷六月丁香| 卡一卡2卡三精品| 69久久夜色精品国产7777| 美女脱光衣服与内衣内裤一区二区三区四区| 久久精品综合一区| aaa国产视频| 66国产精品| 亚洲国产精品综合久久久| 91污在线观看| 欧美激情性xxxxx| 你懂的国产精品永久在线| 九九热免费视频| 日韩欧美国产成人精品免费| 天堂中文在线资源| 国产91色综合久久免费分享| 国产精品久久综合av爱欲tv| 国产中文字幕视频在线观看| 国产精品久久久久久久成人午夜| 91视频国产观看| 欧美激情在线有限公司| 美日韩黄色片| 在线不卡一区| 超碰精品在线观看| 成人久久电影| 中文字幕精品在线观看| 国产精品300页| 人妻少妇精品无码专区| 欧美日韩亚洲国内综合网| 欧美色视频在线观看| 污视频网站在线看| 亚洲精品网站在线观看| 免费久久精品视频| 精品亚洲国产成人av制服丝袜| 成人午夜精品视频| 国产一二三精品| 人体私拍套图hdxxxx| 欧洲日韩一区二区三区| 国产精品精华液网站| 天天躁夜夜躁狠狠是什么心态| 公共露出暴露狂另类av| 毛片视频免费播放| 欧美日韩久久一区| 久久99精品久久久水蜜桃| jvid福利在线一区二区| 亚洲亚洲精品在线观看| 欧美黄色网络| 欧美激情护士| 久久久久久久久免费| 色开心亚洲综合| 麻豆蜜桃在线观看| 2021年精品国产福利在线| 久操视频在线观看| 少妇精品视频一区二区免费看| 国产99在线观看| 精品国产欧美日韩不卡在线观看| 美女网站一区| 日韩三级电影视频| 一区二区三区视频国产日韩| 97欧洲一区二区精品免费| 性色av一区二区三区在线观看| 国产一区二区色噜噜| 亚洲精品久久一区二区三区777| 成人信息集中地欧美| 97视频色精品| 国产精品美女午夜爽爽| 第三区美女视频在线| 国产亚洲一区在线播放| 欧美午夜一区二区三区免费大片| 香蕉视频国产在线观看| 欧美性猛交xxxx乱大交少妇| 久久久久久久香蕉网| 激情av在线| 999福利在线视频| 麻豆国产在线播放| 亚洲精品小说| 亚洲sss视频| 五月婷婷亚洲| 91欧美国产| 国产精品欧美综合在线| 992tv在线观看| 丁香色欲久久久久久综合网| 精品久久久久久久久久久久久久久久久| www日本在线| www亚洲色图| www.国产色| 91桃色在线观看| 久久99精品久久久久久久久久| 人人澡人人添人人爽一区二区| 亚洲精品理论片| 亚洲一区二区乱码| 国产女人aaa级久久久级| 三级毛片在线免费看| 神马影院一区二区三区| 神马欧美一区二区| 成人一级视频| 九色porny自拍视频在线观看| 美女伦理水蜜桃4| 国产二区三区四区| 性一交一乱一伧老太| 日韩视频一区在线观看| 成人免费一级视频| 国产乱视频在线观看播放| 欧美视频精品全部免费观看| 国产精品传媒毛片三区| 成人三级高清视频在线看| 91视频观看免费| 中文字幕人妻无码系列第三区| 91精品啪在线观看麻豆免费| 国产欧美一区二区三区视频在线观看| 91theporn国产在线观看| 国产精品一区在线免费观看| 国产麻豆天美果冻无码视频| 一区二区三区国产豹纹内裤在线| 亚洲精品欧美一区二区三区| 国产精品v日韩精品v欧美精品网站| 亚洲片在线观看| 78色国产精品| 日韩伦理在线一区| 美国美女黄色片| 日韩免费福利电影在线观看| 亚洲成人五区| 国产精品青草久久久久福利99| 午夜久久福利影院| 久久精品盗摄| 日韩视频免费观看高清在线视频| 欧美一区二区三区免费视| 一本色道**综合亚洲精品蜜桃冫| 国产传媒久久文化传媒| 成人丁香基地| 日韩精品福利片午夜免费观看| 99国产精品私拍| 日本韩国一区| 午夜影院免费体验区| 国产精品300页| 自拍欧美日韩| 国产精品666| 欧日韩一区二区三区| 国内精品卡一卡二卡三新区| 97av在线影院| 丝袜诱惑一区二区|