IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android初学 可拖动的浮动按钮(FloatingActionButton )实现 -> 正文阅读

[移动开发]Android初学 可拖动的浮动按钮(FloatingActionButton )实现

参考资源:
android中的坐标系以及获取坐标的方法

效果图如下图所示:

在这里插入图片描述

未完成部分:

  • 按钮会滑动到虚拟导航键盘下面,不知道哪出了问题: 模拟器问题,真机上莫得这个问题
public class MyFloatBtn extends FloatingActionButton {
    private static final String TAG = "MyFloatBtn";
    private int mLastX, mLastY;//按下时的X,Y坐标
    private int mDownX, mDownY;//按下时的X,Y坐标 用来计算移动的距离
    private int mScreenWidth, mScreenHeight;//ViewTree的宽和高
	// 重写了所有的构造函数,因为不知道会用哪种
	// 每个构造函数都进行了数据的初始化,即获取屏幕的高度和宽度
    public MyFloatBtn(Context context) {
        super(context);
        initData(context);
    }

    public MyFloatBtn(Context context, AttributeSet attrs) {
        super(context, attrs);
        initData(context);
    }

    public MyFloatBtn(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData(context);
    }
    // 初始化数据:高度和宽度。看上去没啥问题,但是运行的时候浮动按钮的一部分会跑到虚拟导航栏的下面,也就是说获取的高度超过了显示的部分,但是宽度是正常的。
    private void initData(Context context) {
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        mScreenHeight = metrics.heightPixels;
        mScreenWidth = metrics.widthPixels;
    }

	// 重写onTouchEvent方法,主要在这个方法里面来处理点击和拖动事件
    @Override
    public boolean onTouchEvent(@NonNull MotionEvent ev) {
        int actionId = ev.getAction();
        // Log.i(TAG, "onTouchEvent: " + actionId);
        switch (actionId) {
            // 无论是拖动还是点击 都需要先按下去,所以在这个case里记录按钮按下时的坐标
            case MotionEvent.ACTION_DOWN:
                // Log.i(TAG, "onTouchEvent: " + "DOWN");
                mLastX = (int) ev.getRawX();// getRawX: 获取的距离屏幕边缘的距离,而不是组件的
                mLastY = (int) ev.getRawY();
                mDownX = mLastX;// 判断是点击事件还是拖动事件时需要用到
                mDownY = mLastY;
                break;
            // 抬起事件:无论是拖动还是点击,完成之后都需要抬起按钮,在这个case里判断是拖动按钮还是点击按钮,主要是通过移动的距离来判断的,如果移动的距离超过5则认为是拖动,否则就是点击事件。如果是拖动事件则需要在此消费掉此事件,不会再执行onClick的方法。
            case MotionEvent.ACTION_UP:
                // Log.i(TAG, "onTouchEvent: " + "UP");
                if (calculateDistance(mDownX, mDownY, (int) ev.getRawX(), (int) ev.getRawY()) <= 5) {
                    Log.i(TAG, "onTouchEvent: 点击事件");
                } else {
                    Log.i(TAG, "onTouchEvent: 拖动事件");
                    // 消费掉此事件
                    return true;
                }
                break;
            // 移动事件:根据移动之后的位置进行重绘
            case MotionEvent.ACTION_MOVE:
                int dx = (int) ev.getRawX() - mLastX;//x方向的偏移量
                int dy = (int) ev.getRawY() - mLastY;//y方向的偏移量
                // getLeft(): Left position of this view relative to its parent.
                // 计算组件此时的位置,距离父容器上下左右的距离=偏移量 + 原来的距离
                int left = getLeft() + dx;
                int top = getTop() + dy;
                int right = getRight() + dx;
                int bottom = getBottom() + dy;
                /*if (dy < 0) {
                    Log.i(TAG, "onTouchEvent: 向上拖动");
                } else {
                    Log.i(TAG, "onTouchEvent: 向下拖动");
                }
                if (dx < 0) {
                    Log.i(TAG, "onTouchEvent: 向左拖动");
                } else {
                    Log.i(TAG, "onTouchEvent: 向右拖动");
                }*/
                mLastX = (int) ev.getRawX();
                mLastY = (int) ev.getRawY();
                if (top < 0) {
                    // 移出了上边界
                    top = 0;
                    bottom = getHeight();
                }
                if (left < 0) {
                    // 移出了左边界
                    left = 0;
                    right = getWidth();
                }
                if (bottom > mScreenHeight) {
                    // 移出了下边界
                    bottom = mScreenHeight;
                    top = bottom - getHeight();
                }
                if (right > mScreenWidth) {
                    // 移出了右边界
                    right = mScreenWidth;
                    left = right - getWidth();
                }
                layout(left, top, right, bottom);
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }
	// get the distance between (downX, downY) and (lastX, lastY)
    private int calculateDistance(int downX, int downY, int lastX, int lastY) {
        return (int) Math.sqrt(Math.pow(1.0f * (lastX - downX), 2.0) + Math.pow((lastY - downY) * 1.0f, 2.0));
    }
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <work.wxmx.floatbtntest.MyFloatBtn
        android:src="@drawable/ic_baseline_archive_24"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章           查看所有文章
加:2021-07-28 00:17:13  更:2021-07-28 00:17:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 7:30:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码