栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

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

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

不多说 先上效果

一个自定义的view 使用方式也很简单

然后先看下源码

**
 * Created by weizhenbin on 16/6/1.
 * 

* 一个可以随意拖动的view */ public class VanishView extends TextView { private Context context; private WindowManager windowManager; private ImageView iv; private int statusHeight = 0; private int dx = 0; private int dy = 0; private Bitmap tmp; private float downX = 0; 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 { @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的区别

getX和getY 是相对于view自身的,getRawX和getRawY是像对屏幕的,这里还要扣除掉状态栏的高度。

2.移动

 windowManager.updateViewLayout(iv, mWindowLayoutParams);

3.使用ValueAnimator属性动画实现回弹效果

这里自定义了Typeevaluator实现点的位移动画

class MyTypeevaluator implements Typeevaluator {

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/155067.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号