溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

怎么在Android中實(shí)現(xiàn)QQ消息提示點(diǎn)拖拽功能

發(fā)布時(shí)間:2021-05-22 16:51:41 來(lái)源:億速云 閱讀:125 作者:Leah 欄目:移動(dòng)開(kāi)發(fā)

怎么在Android中實(shí)現(xiàn)QQ消息提示點(diǎn)拖拽功能?相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

一個(gè)自定義的view 使用方式也很簡(jiǎn)單

<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/>
 * 一個(gè)可以隨意拖動(dòng)的view
 */
public class VanishView extends TextView {
 private Context context;
 /**窗口管理器*/
 private WindowManager windowManager;

 /**用來(lái)存儲(chǔ)鏡像的imageview*/
 private ImageView iv;

 /** 狀態(tài)欄高度*/
 private int statusHeight = 0;

 /**按下的坐標(biāo)x 相對(duì)于view自身*/
 private int dx = 0;

 /**按下的坐標(biāo)y 相對(duì)于view自身*/
 private int dy = 0;

 /**鏡像bitmap*/
 private Bitmap tmp;

 /**按下的坐標(biāo)x 相對(duì)于屏幕*/
 private float downX = 0;

 /**按下的坐標(biāo)y 相對(duì)于屏幕*/
 private float downY = 0;

 /**屬性動(dòng)畫(huà) 用于回彈效果*/
 private ValueAnimator animator;

 /**窗口參數(shù)*/
 private WindowManager.LayoutParams mWindowLayoutParams;

 /**接口對(duì)象*/
 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;
 }

 /**
  * 構(gòu)建一個(gè)窗口 用于存放和移動(dòng)鏡像
  * */
 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);
 }


 /**
  * 使用屬性動(dòng)畫(huà) 實(shí)現(xiàn)緩慢回彈效果
  * */
 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();
 }

 /**
  * 計(jì)算兩點(diǎn)的距離
  */
 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;

 }

 /**
  * 獲取狀態(tài)欄的高度
  */
 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;
  }
 }

 /**事件回調(diào)借口*/
 public interface OnListener{
  void onDismiss();
 }

 public void setListener(OnListener listener) {
  this.listener = listener;
 }

實(shí)現(xiàn)這一功能其實(shí)也不難,這個(gè)功能涉及到以下幾個(gè)知識(shí)點(diǎn)

使用WindowManager添加一個(gè)view
使用ValueAnimator屬性動(dòng)畫(huà)實(shí)現(xiàn)回彈效果
getX和getRawX,getY和getRawY的區(qū)別

1.使用WindowManager添加一個(gè)view

 /**
  * 構(gòu)建一個(gè)窗口 用于存放和移動(dòng)鏡像
  * */
 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);
 }

這一步是為了投影一個(gè)鏡像來(lái)達(dá)到拖動(dòng)view的一個(gè)假像效果,使用imageview來(lái)顯示。這里為了使投影沒(méi)用偏移需要了解getX getRawX getY getRawY的區(qū)別

怎么在Android中實(shí)現(xiàn)QQ消息提示點(diǎn)拖拽功能

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

2.移動(dòng)

 windowManager.updateViewLayout(iv, mWindowLayoutParams);

3.使用ValueAnimator屬性動(dòng)畫(huà)實(shí)現(xiàn)回彈效果

這里自定義了TypeEvaluator實(shí)現(xiàn)點(diǎn)的位移動(dòng)畫(huà)

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;
  }
 }


 /**
  * 使用屬性動(dòng)畫(huà) 實(shí)現(xiàn)緩慢回彈效果
  * */
 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();
 }

通過(guò)屬性動(dòng)畫(huà)實(shí)現(xiàn)一個(gè)回彈效果

4.觸發(fā)消失的時(shí)機(jī)

 /**
  * 計(jì)算兩點(diǎn)的距離
  */
 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;
 }

計(jì)算兩點(diǎn)之間的距離來(lái)觸發(fā)一個(gè)回調(diào)事件。

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);
    }

Android是什么

Android是一種基于Linux內(nèi)核的自由及開(kāi)放源代碼的操作系統(tǒng),主要使用于移動(dòng)設(shè)備,如智能手機(jī)和平板電腦,由美國(guó)Google公司和開(kāi)放手機(jī)聯(lián)盟領(lǐng)導(dǎo)及開(kāi)發(fā)。

看完上述內(nèi)容,你們掌握怎么在Android中實(shí)現(xiàn)QQ消息提示點(diǎn)拖拽功能的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI