转自http://www.jianshu.com/p/ba3e5fc5cff1

实现思路

  1. 通过重写控件的onTouchEvent方法监听触摸效果。
  2. 通过View的setX()和setY()方法实现移动。
  3. 使用属性动画实现边缘吸附效果。

源代码没多少行,这里先把代码线上。此处我是继承了FloatingActionButton,使它拥有了拖拽移动的功能。

public class DragFloatActionButton extends FloatingActionButton{private int screenWidth;private int screenHeight;private int screenWidthHalf;private int statusHeight;public DragFloatActionButton(Context context) {super(context);init();}public DragFloatActionButton(Context context, AttributeSet attrs) {super(context, attrs);init();}public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init(){screenWidth= DisplayUtil.getMobileWidth(getContext());screenWidthHalf=screenWidth/2;screenHeight=DisplayUtil.getMobileHeight(getContext());statusHeight=DisplayUtil.getStatusHeight((Activity) getContext());}private int lastX;private int lastY;private boolean isDrag;@Overridepublic boolean onTouchEvent(MotionEvent event) {int rawX = (int) event.getRawX();int rawY = (int) event.getRawY();switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:isDrag=false;getParent().requestDisallowInterceptTouchEvent(true);lastX=rawX;lastY=rawY;break;case MotionEvent.ACTION_MOVE:isDrag=true;//计算手指移动了多少int dx=rawX-lastX;int dy=rawY-lastY;//这里修复一些华为手机无法触发点击事件的问题int distance= (int) Math.sqrt(dx*dx+dy*dy);if(distance==0){isDrag=false;break;}float x=getX()+dx;float y=getY()+dy;//检测是否到达边缘 左上右下x=x<0?0:x>screenWidth-getWidth()?screenWidth-getWidth():x;y=y<statusHeight?statusHeight:y+getHeight()>screenHeight?screenHeight-getHeight():y;setX(x);setY(y);lastX=rawX;lastY=rawY;//Log.i("getX="+getX()+";getY="+getY()+";screenHeight="+screenHeight);break;case MotionEvent.ACTION_UP:if(isDrag){//恢复按压效果setPressed(false);Log.i("getX="+getX()+";screenWidthHalf="+screenWidthHalf);if(rawX>=screenWidthHalf){animate().setInterpolator(new DecelerateInterpolator()).setDuration(500).xBy(screenWidth-getWidth()-getX()).start();}else {ObjectAnimator oa=ObjectAnimator.ofFloat(this,"x",getX(),0);oa.setInterpolator(new DecelerateInterpolator());oa.setDuration(500);oa.start();}}break;}//如果是拖拽则消耗事件,否则正常传递即可。return isDrag || super.onTouchEvent(event);}
}
<test.com.customview.DragFloatActionButtonandroid:id="@+id/but"android:layout_width="30dp"android:layout_height="30dp"/>

说明:这边是继承了FloatingActionButton,这是design的风格,悬浮按钮,默认圆形的背景色,如果你要设置图片会放入中间,

所以你想让这个悬浮按钮是一个图片,可以继承ImageButton,这样就可以了。

2,代码DisplayUtil没有贴出来,如下

/*** 获得屏幕相关的辅助类****/
public class ScreenUtils
{private ScreenUtils(){/* cannot be instantiated */throw new UnsupportedOperationException("cannot be instantiated");}/*** 获得屏幕高度** @param context* @return*/public static int getScreenWidth(Context context){WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.widthPixels;}/*** 获得屏幕宽度** @param context* @return*/public static int getScreenHeight(Context context){WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);DisplayMetrics outMetrics = new DisplayMetrics();wm.getDefaultDisplay().getMetrics(outMetrics);return outMetrics.heightPixels;}/*** 获得状态栏的高度** @param context* @return*/public static int getStatusHeight(Context context){int statusHeight = -1;try{Class<?> clazz = Class.forName("com.android.internal.R$dimen");Object object = clazz.newInstance();int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());statusHeight = context.getResources().getDimensionPixelSize(height);} catch (Exception e){e.printStackTrace();}return statusHeight;}/*** 获取当前屏幕截图,包含状态栏** @param activity* @return*/public static Bitmap snapShotWithStatusBar(Activity activity){View view = activity.getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmap bmp = view.getDrawingCache();int width = getScreenWidth(activity);int height = getScreenHeight(activity);Bitmap bp = null;bp = Bitmap.createBitmap(bmp, 0, 0, width, height);view.destroyDrawingCache();return bp;}/*** 获取当前屏幕截图,不包含状态栏** @param activity* @return*/public static Bitmap snapShotWithoutStatusBar(Activity activity){View view = activity.getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmap bmp = view.getDrawingCache();Rect frame = new Rect();activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);int statusBarHeight = frame.top;int width = getScreenWidth(activity);int height = getScreenHeight(activity);Bitmap bp = null;bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height- statusBarHeight);view.destroyDrawingCache();return bp;}}

代码很简单,
手指按下
首先是处理手指按压下的事件,这里我们把拖拽标识符设置为false并记录当前点击的屏幕坐标。然后我们在移动事件处。
手指移动
这里我们把拖拽标识符设置为true,因为手指移动了。然后我们需要计算手指移动了多少偏移量

//计算手指移动了多少
int dx=rawX-lastX;
int dy=rawY-lastY;

而后的两行代码表示控件需要移动的具体距离,后面有一个简单的边缘检测计算。最终通过调用setX以及setY方法实现控件的移动。
手指松开
这里如果是拖拽动作我们才需要处理自己的逻辑否则直接跳过即可。在这里我们首先恢复了按钮的按压效果,在源代码中找到setPressed(boolean)方法,这是处理按钮点击效果用的,在这里当手指松开后我们需要恢复按钮原来的效果。然后在判断控件需要往哪边吸附,吸附的过程就是做属性动画而已,原理还是不断的改变setX方法让按钮靠边移动

总结

这种实现方式,我们能正常的使用控件的单击时间和长按事件,因为只有当控件拖拽的时候我们才自己消耗事件否则全部交给系统处理。这是一种比较好的实现方式,通过这个例子其实我们还能实现更多的控件移动效果。事实上只需要改变所继承的控件类型就可以了

PS:最近发现在部分华为手机上无法触发点击事件,调试发现当我手指按压的时候会一直触发MotionEvent.ACTION_MOVE事件而事实上我手指一点都没有动,且Log出现的数据显示移动距离一直是0.坑爹。只能加一个距离判断了。上面的代码已经修复了这个问题。

Android 可拖拽悬浮按钮相关推荐

  1. vue移动端拖拽悬浮按钮

    vue移动端拖拽悬浮按钮 功能介绍: 大致需求: 整体思路: 简单效果展示: 具体实现: 一.position:fixed布局: 二.touch事件绑定: 三.页面引入: 功能介绍: 在移动端开发中, ...

  2. android可拖拽悬浮控件和Kotlin的可拖拽悬浮控件/可拖拽悬浮按钮带Demo附件

    本文讲解的是一个实现了可拖拽的悬浮按钮,并添加了吸附边框的功能. 借鉴于:https://www.jianshu.com/p/4f55bcbc1b83 在此之前,先了解下其简单的使用方式吧: 原文地址 ...

  3. Android 自定义可拖拽悬浮按钮

    一.添加依赖 compile 'com.android.support:design:26.1.0' 后面的版本号要和 implementation 'com.android.support:appc ...

  4. android 浮动按钮拖拽,小程序拖拽浮动按钮

    小程序拖拽浮动按钮 2019-5-22    分类: 小程序 小程序 浮动  拖拽 按钮 不借助movable-area自带的组件,实现拖拽效果 wxml + js: var startPoint; ...

  5. 可拖拽悬浮球,仿Assistive Touch弹出窗口

    可拖拽悬浮球,仿Assistive Touch弹出窗口 悬浮球 layout中使用DragFloatActionButton 最重要的事情!!!一定要给DragFloatActionButton设置点 ...

  6. android布局黑色字体颜色,Android开发之FloatingActionButton悬浮按钮基本使用、字体、颜色用法示例...

    本文实例讲述了Android开发之FloatingActionButton悬浮按钮基本使用.字体.颜色用法.分享给大家供大家参考,具体如下: 这里主要讲: FloatingActionsMenu自定义 ...

  7. android 按键会触发ontouch吗?_Android实现炫酷的拖拽浮动按钮

    IOS的Assistive Touch效果很炫酷,可以任意拖拽,同时点击后会展开菜单栏.然而,这不只是IOS的特权,Android也可以实现.但是由于悬浮窗需要申请权限,所以本文仅在app内实现,可以 ...

  8. Android自定义可移动悬浮按钮

    <com.example.notepad2.DragFloatActionButton android:id="@+id/fb" android:layout_height= ...

  9. Android自定义可移动悬浮按钮,附大厂真题面经

    android:layout_width="wrap_content" app:borderWidth="0dp" app:backgroundTint=&qu ...

最新文章

  1. Java 必须掌握的 12 种 Spring 常用注解!
  2. python 为何要学16进制,从十六进制Python中的补
  3. Archive引擎初探
  4. Laravel- 数据库迁移
  5. TCP为什么是三次握手和四次挥手
  6. C 语言 函数调用栈
  7. java遍历map_java遍历Map的几种方法
  8. String练习代码保存
  9. go web db每次关闭_竟然不用写代码!一款可视化 Web 管理后台生成工具
  10. 建立任务程序直接执行网页(.net)
  11. 是什么让spring 5放弃了使用Guava Cache?
  12. Atitit.获取某个服务 网络邻居列表 解决方案
  13. 献给和我一样迷茫的人们,9天准备笔试上岸中科大MPM工程硕士的心路历程(8820字)
  14. 贼有趣:朱茵变杨幂,人工智能换脸让明星不再担心自己演技?
  15. C语言零基础,入门应该知道的事
  16. 科研写作之Origin使用心得
  17. systemview简介
  18. matlab-高数 plot 二维画图 绝对值函数 取整函数 分段函数
  19. EC-PCA: 利润中心记账流程
  20. HTML5 代码规范

热门文章

  1. 剪切板是计算机系统,必备的高效小工具Ditto轻松记录复制剪切板内容-win7剪切板...
  2. 企业如何开展网络营销—壹间网络
  3. Hbuilder X APP开发 iPhoneX以上型号屏幕底部覆盖返回条适应问题
  4. 如何设计和生成游戏的激活码
  5. 微信昵称可以加雪花了,个性又好看
  6. 闲话handle和handler
  7. 第十阶段 -- Flask框架03:【Jinja2模板01:模板;过滤器;控制语句if for】
  8. 四叉树和希尔伯特曲线做空间索引
  9. 在使用dedecms的channel标签来调子栏目的时候,指定 “type=son typeid=x” 发现currentstyle无效
  10. Google群星闪耀 iGoogle最亮眼