麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統 > 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開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 久久精品中文字幕一区二区三区 | 色a综合 | 欧美一区二区三区不卡免费观看 | 日本一道aⅴ不卡免费播放 久久久久久久高清 | 黄色成年在线观看 | 男男啪羞羞视频网站 | h视频在线播放 | 成人在线观看免费观看 | 久久国产秒 | 久久久久久久99 | 精品国产91久久久久久久妲己 | 欧美黄色免费视频 | 一区二区久久电影 | 九九精品在线 | 国内免费视频成人精品 | 久久精品国产精品亚洲 | 一级看片免费视频 | 国产午夜亚洲精品 | 亚洲免费视频大全 | 黄污视频在线看 | 日韩黄色成人 | 亚洲一二区精品 | 精品一区二区免费视频视频 | 青青国产在线视频 | 国产欧美一区二区三区免费看 | 黄色片在线播放 | 欧美性受ⅹ╳╳╳黑人a性爽 | 免费男女乱淫真视频 | 毛片中文字幕 | 日韩黄色成人 | 成人激情在线 | 精品一区二区三区中文字幕老牛 | 国产精品高潮99久久久久久久 | 一区二区精品视频 | 午夜在线成人 | 国产亚洲精品影达达兔 | 欧美一级片网站 | 色a综合| 91精品国产91久久久久久 | 免费视频aaa | 亚洲精品欧美二区三区中文字幕 |