a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 系統 > 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開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 婷婷色国产偷v国产偷v小说 | 国产一页 | 国模精品视频一区二区 | 久久a v视频 | 欧美日韩视频在线观看一区 | 亚洲欧美激情视频 | 欧美日韩一区二区不卡 | 久久精品亚洲欧美日韩精品中文字幕 | 久久国产精品无码网站 | www.av7788.com| 亚洲精品一区二区三区在线播放 | 国产精品成人免费视频 | 国产一区二区久久 | 蜜桃一本色道久久综合亚洲精品冫 | 北条麻妃国产九九九精品小说 | 蜜桃官网 | 日本一区二区视频在线 | 国产精品一区二区三区在线 | 欧美成人精品一区二区男人看 | 欧美精品一区二区在线播放 | 综合激情av | 国产精品视频久久 | 欧美成人黄激情免费视频 | 日韩av一区三区 | 97人人草| 欧美日韩三级 | 成人福利在线观看 | 欧美一区二区在线观看 | 国产日韩精品视频 | 日本欧美国产 | 精品视频一区二区在线观看 | 色婷婷av一区二区三区软件 | 国产成人综合在线 | 中文字幕视频免费观看 | 91精品久久久久久久久 | 欧美一级毛片免费观看 | 欧美国产日韩精品 | 亚洲h视频| 国产成人免费 | 91亚洲免费| 国产区免费观看 |