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

首頁 > 系統 > Android > 正文

Android仿QQ消息提示點拖拽功能

2019-10-21 21:26:29
字體:
來源:轉載
供稿:網友

很久以前,發現QQ有一個很有趣的功能,就是未讀消息的紅點是可以拖拽的,而且在任何地方都可以隨意拖拽,并且有一個彈性的動畫,非常有趣,而且也是一個非常方便的功能,于是總想仿制一個,雖說仿制,但也只是他的拖拽功能,彈性效果還是能力有限。

不多說 先上效果

Android,仿QQ,提示點,拖拽

一個自定義的view 使用方式也很簡單

<com.weizhenbin.show.widget.VanishView  android:layout_width="30dp"  android:layout_height="30dp"  android:text="5"  android:layout_alignParentBottom="true"  android:gravity="center"  android:textColor="#fff"  android:id="@+id/vv"  android:layout_marginBottom="35dp"  android:layout_marginLeft="80dp"  android:background="@drawable/shape_red_bg"/>

然后先看下源碼

 

** * Created by weizhenbin on 16/6/1. * <p/> * 一個可以隨意拖動的view */public class VanishView extends TextView { private Context context; /**窗口管理器*/ private WindowManager windowManager; /**用來存儲鏡像的imageview*/ private ImageView iv; /** 狀態欄高度*/ private int statusHeight = 0; /**按下的坐標x 相對于view自身*/ private int dx = 0; /**按下的坐標y 相對于view自身*/ private int dy = 0; /**鏡像bitmap*/ private Bitmap tmp; /**按下的坐標x 相對于屏幕*/ private float downX = 0; /**按下的坐標y 相對于屏幕*/ private float downY = 0; /**屬性動畫 用于回彈效果*/ private ValueAnimator animator; /**窗口參數*/ private WindowManager.LayoutParams mWindowLayoutParams; /**接口對象*/ private OnListener listener; public VanishView(Context context) {  super(context);  init(context); } public VanishView(Context context, AttributeSet attrs) {  super(context, attrs);  init(context); } public VanishView(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  init(context); } private void init(Context context) {  this.context = context;  windowManager = ((Activity) context).getWindowManager();  statusHeight = getStatusHeight(context); } @Override public boolean onTouchEvent(MotionEvent event) {  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    dx = (int) event.getX();    dy = (int) event.getY();    downX = event.getRawX();    downY = event.getRawY();    addWindow(context, event.getRawX(), event.getRawY());    setVisibility(INVISIBLE);    break;   case MotionEvent.ACTION_MOVE:    mWindowLayoutParams.x = (int) (event.getRawX() - dx);    mWindowLayoutParams.y = (int) (event.getRawY() - statusHeight - dy);    windowManager.updateViewLayout(iv, mWindowLayoutParams);    break;   case MotionEvent.ACTION_UP:    int distance=distance(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY));    if(distance<400) {     scroll(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY));    }else {     if(listener!=null){      listener.onDismiss();     }     windowManager.removeView(iv);    }    break;  }  return true; } /**  * 構建一個窗口 用于存放和移動鏡像  * */ private void addWindow(Context context, float downX, float dowmY) {  mWindowLayoutParams = new WindowManager.LayoutParams();  mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  iv = new ImageView(context);  mWindowLayoutParams.format = PixelFormat.RGBA_8888;  mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;  mWindowLayoutParams.x = (int) (downX - dx);  mWindowLayoutParams.y = (int) (dowmY - statusHeight - dy);  //獲取view的鏡像bitmap  this.setDrawingCacheEnabled(true);  tmp = Bitmap.createBitmap(this.getDrawingCache());  //釋放緩存  this.destroyDrawingCache();  iv.setImageBitmap(tmp);  windowManager.addView(iv, mWindowLayoutParams); } /**  * 使用屬性動畫 實現緩慢回彈效果  * */ private void scroll(MyPoint start, MyPoint end) {  animator = ValueAnimator.ofObject(new MyTypeEvaluator(), start, end);  animator.setDuration(200);  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {   @Override   public void onAnimationUpdate(ValueAnimator animation) {    MyPoint point = (MyPoint) animation.getAnimatedValue();    mWindowLayoutParams.x = (int) (point.x - dx);    mWindowLayoutParams.y = (int) (point.y - statusHeight - dy);    windowManager.updateViewLayout(iv, mWindowLayoutParams);   }  });  animator.addListener(new AnimatorListenerAdapter() {   @Override   public void onAnimationEnd(Animator animation) {    super.onAnimationEnd(animation);    windowManager.removeView(iv);    setVisibility(VISIBLE);   }  });  animator.start(); } /**  * 計算兩點的距離  */ private int distance(MyPoint point1, MyPoint point2) {  int distance = 0;  if (point1 != null && point2 != null) {   float dx = point1.x - point2.x;   float dy = point1.y - point2.y;   distance = (int) Math.sqrt(dx * dx + dy * dy);  }  return distance; } /**  * 獲取狀態欄的高度  */ private static int getStatusHeight(Context context) {  int statusHeight = 0;  Rect localRect = new Rect();  ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);  statusHeight = localRect.top;  if (0 == statusHeight) {   Class<?> localClass;   try {    localClass = Class.forName("com.android.internal.R$dimen");    Object localObject = localClass.newInstance();    int i5 = Integer.parseInt(localClass.getField("status_bar_height").get(localObject).toString());    statusHeight = context.getResources().getDimensionPixelSize(i5);   } catch (Exception e) {    e.printStackTrace();   }  }  return statusHeight; } class MyPoint {  float x;  float y;  public MyPoint(float x, float y) {   this.x = x;   this.y = y;  }  @Override  public String toString() {   return "MyPoint{" +     "x=" + x +     ", y=" + y +     '}';  } } class MyTypeEvaluator implements TypeEvaluator<MyPoint> {  @Override  public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) {   MyPoint point = startValue;   point.x = startValue.x + fraction * (endValue.x - startValue.x);   point.y = startValue.y + fraction * (endValue.y - startValue.y);   return point;  } } /**事件回調借口*/ public interface OnListener{  void onDismiss(); } public void setListener(OnListener listener) {  this.listener = listener; }

實現這一功能其實也不難,這個功能涉及到以下幾個知識點

使用WindowManager添加一個view
使用ValueAnimator屬性動畫實現回彈效果
getX和getRawX,getY和getRawY的區別

1.使用WindowManager添加一個view

 /**  * 構建一個窗口 用于存放和移動鏡像  * */ private void addWindow(Context context, float downX, float dowmY) {  mWindowLayoutParams = new WindowManager.LayoutParams();  mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  iv = new ImageView(context);  mWindowLayoutParams.format = PixelFormat.RGBA_8888;  mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;  mWindowLayoutParams.x = (int) (downX - dx);  mWindowLayoutParams.y = (int) (dowmY - statusHeight - dy);  //獲取view的鏡像bitmap  this.setDrawingCacheEnabled(true);  tmp = Bitmap.createBitmap(this.getDrawingCache());  //釋放緩存  this.destroyDrawingCache();  iv.setImageBitmap(tmp);  windowManager.addView(iv, mWindowLayoutParams); }

這一步是為了投影一個鏡像來達到拖動view的一個假像效果,使用imageview來顯示。這里為了使投影沒用偏移需要了解getX getRawX getY getRawY的區別

Android,仿QQ,提示點,拖拽

getX和getY 是相對于view自身的,getRawX和getRawY是像對屏幕的,這里還要扣除掉狀態欄的高度。

2.移動

 windowManager.updateViewLayout(iv, mWindowLayoutParams);

3.使用ValueAnimator屬性動畫實現回彈效果

這里自定義了TypeEvaluator實現點的位移動畫

class MyTypeEvaluator implements TypeEvaluator<MyPoint> {  @Override  public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) {   MyPoint point = startValue;   point.x = startValue.x + fraction * (endValue.x - startValue.x);   point.y = startValue.y + fraction * (endValue.y - startValue.y);   return point;  } } /**  * 使用屬性動畫 實現緩慢回彈效果  * */ private void scroll(MyPoint start, MyPoint end) {  animator = ValueAnimator.ofObject(new MyTypeEvaluator(), start, end);  animator.setDuration(200);  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {   @Override   public void onAnimationUpdate(ValueAnimator animation) {    MyPoint point = (MyPoint) animation.getAnimatedValue();    mWindowLayoutParams.x = (int) (point.x - dx);    mWindowLayoutParams.y = (int) (point.y - statusHeight - dy);    windowManager.updateViewLayout(iv, mWindowLayoutParams);   }  });  animator.addListener(new AnimatorListenerAdapter() {   @Override   public void onAnimationEnd(Animator animation) {    super.onAnimationEnd(animation);    windowManager.removeView(iv);    setVisibility(VISIBLE);   }  });  animator.start(); }

通過屬性動畫實現一個回彈效果

4.觸發消失的時機

 /**  * 計算兩點的距離  */ private int distance(MyPoint point1, MyPoint point2) {  int distance = 0;  if (point1 != null && point2 != null) {   float dx = point1.x - point2.x;   float dy = point1.y - point2.y;   distance = (int) Math.sqrt(dx * dx + dy * dy);  }  return distance; }

計算兩點之間的距離來觸發一個回調事件。

int distance=distance(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY));    if(distance<400) {     scroll(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY));    }else {     if(listener!=null){      listener.onDismiss();     }     windowManager.removeView(iv);    }

代碼分析就到這里,實現這個功能的核心代碼都在這里。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩电影大片中文字幕| 在线观看欧美日韩| 亚洲国产私拍精品国模在线观看| 欧美电影免费观看大全| 欧美在线一级va免费观看| 欧美成人午夜激情视频| 91精品一区二区| 欧美日韩国产999| 成人欧美一区二区三区黑人孕妇| 欧美日韩福利视频| 欧美日韩在线看| 亚洲精品动漫久久久久| 正在播放亚洲1区| 国产精品久久久久久久app| 欧美电影免费在线观看| 亚洲天堂2020| 136fldh精品导航福利| 自拍偷拍亚洲一区| 97视频在线观看播放| 成人精品一区二区三区电影免费| 欧美日韩成人在线观看| 亚洲欧美日韩综合| 成人精品在线视频| 日韩美女写真福利在线观看| 国产精品免费一区豆花| 69视频在线播放| 国产成人精品电影久久久| 在线日韩欧美视频| 亚洲精品综合久久中文字幕| 久久99热精品这里久久精品| 91欧美精品午夜性色福利在线| 免费97视频在线精品国自产拍| 亚洲视频在线观看网站| 欧美日韩色婷婷| 国产精品偷伦一区二区| 91精品久久久久久久久久久久久久| 免费不卡在线观看av| 国产精品一区二区三区毛片淫片| 国产女同一区二区| 成人网欧美在线视频| 欧美午夜激情视频| 日韩国产一区三区| 精品久久久国产精品999| 国产精品综合久久久| 欧美性色xo影院| 欧美大片欧美激情性色a∨久久| 伊人男人综合视频网| 亚洲电影免费在线观看| 国产不卡精品视男人的天堂| 日韩国产在线播放| 日韩国产高清视频在线| 久久影视电视剧免费网站| 亚洲国产成人久久综合| 欧美色另类天堂2015| 欧洲亚洲在线视频| 亚洲视频999| 国产日本欧美在线观看| 一本色道久久88综合亚洲精品ⅰ| 精品久久香蕉国产线看观看亚洲| 久久影视电视剧免费网站清宫辞电视| 欧美成人黑人xx视频免费观看| 久久精品最新地址| 国产精品综合不卡av| 欧美成aaa人片免费看| 国产精品黄色影片导航在线观看| 欧美日韩国产成人在线观看| 91高清视频在线免费观看| 成人亲热视频网站| 在线观看欧美视频| 亚洲自拍偷拍色片视频| 亚洲黄色在线看| 久久天天躁夜夜躁狠狠躁2022| 欧美激情一区二区三区成人| 日本电影亚洲天堂| 欧美大码xxxx| 亚洲精品久久久久久久久| 不卡av在线播放| 91免费看国产| 国产一区深夜福利| 久久精品电影一区二区| 日韩av免费观影| 91免费人成网站在线观看18| 91精品国产九九九久久久亚洲| 永久免费看mv网站入口亚洲| 欧美视频中文在线看| 综合136福利视频在线| 欧美视频中文在线看| 久久天天躁狠狠躁老女人| 成人美女免费网站视频| 国产日韩欧美夫妻视频在线观看| 欧美激情在线狂野欧美精品| 日韩中文综合网| 精品国产一区二区三区久久久狼| 国内精品视频久久| 草民午夜欧美限制a级福利片| 国产精品免费看久久久香蕉| 欧美尺度大的性做爰视频| 欧美激情xxxx性bbbb| 欧美在线观看日本一区| 欧美日韩综合视频网址| 日韩欧美中文字幕在线播放| 日韩精品在线看| 久久久国产精品亚洲一区| 久久91亚洲人成电影网站| 中文字幕亚洲色图| 亚洲性无码av在线| 91国产在线精品| 日韩欧美主播在线| 久久久久久久激情视频| 91香蕉嫩草影院入口| zzijzzij亚洲日本成熟少妇| 97视频在线观看网址| 亚洲最新av在线网站| 26uuu久久噜噜噜噜| 久久精品国产69国产精品亚洲| 亚洲第一区中文字幕| 欧洲永久精品大片ww免费漫画| 日韩视频―中文字幕| 一区二区在线免费视频| 91超碰中文字幕久久精品| 大量国产精品视频| 国产亚洲激情在线| 日本亚洲欧洲色| 日韩视频免费在线观看| 亚洲精品二三区| 亚洲自拍av在线| 精品久久香蕉国产线看观看亚洲| 国产日韩欧美日韩大片| 欧美午夜精品久久久久久人妖| 久久在精品线影院精品国产| 北条麻妃99精品青青久久| 日本高清不卡的在线| 中文字幕日韩精品有码视频| 91在线无精精品一区二区| 亚洲国产精品视频在线观看| 欧美极品欧美精品欧美视频| 92看片淫黄大片看国产片| 欧美日韩中文在线| 国产精品高潮呻吟久久av黑人| 亚洲女成人图区| 亚洲视频综合网| 亚洲视频欧洲视频| 91精品久久久久久久久青青| 欧美在线一级视频| 色狠狠av一区二区三区香蕉蜜桃| 国产精品99久久久久久www| www.日韩av.com| 国产欧美日韩免费看aⅴ视频| 成人免费观看网址| 91网站免费看| 自拍偷拍亚洲一区| 久久久久久久亚洲精品| 免费99精品国产自在在线| www.xxxx欧美| 成人国产精品av| 色婷婷成人综合| 91麻豆国产语对白在线观看| 国产欧美精品一区二区三区介绍| 亚洲欧美日韩天堂一区二区| 91免费欧美精品| 精品视频9999| 亚洲影院高清在线| 91精品美女在线| 欧美成人午夜激情在线|