android开发分享Android仿QQ消息提示点拖拽功能

很久以前,发现qq有一个很有趣的功能,就是未读消息的红点是可以拖拽的,而且在任何地方都可以随意拖拽,并且有一个弹性的动画,非常有趣,而且也是一个非常方便的功能,于是总想仿制

很久以前,发现qq有一个很有趣的功能,就是未读消息的红点是可以拖拽的,而且在任何地方都可以随意拖拽,并且有一个弹性的动画,非常有趣,而且也是一个非常方便的功能,于是总想仿制一个,虽说仿制,但也只是他的拖拽功能,弹性效果还是能力有限。

上述就是android开发分享Android仿QQ消息提示点拖拽功能的全部内容,如果对大家有所用处且需要了解更多关于Android学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

不多说 先上效果

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

代码分析就到这里,实现这个功能的核心代码都在这里。

以上就是android开发分享Android仿QQ消息提示点拖拽功能的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/937773.html

(0)
上一篇 2021年11月12日
下一篇 2021年11月12日

精彩推荐