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可以自由拖动的View 实现自动吸边并且可以绕开某一位置 -> 正文阅读

[移动开发]Android可以自由拖动的View 实现自动吸边并且可以绕开某一位置

自定义的可以随意拖动并自动贴边的View

自定义view的效果 可以自动绕开某一个view


自定义View演示
接下来开始讲解代码

代码部分

1.自定义View

  1. 要自定义一个View ,当然可以继承任何View,也可以把我的代码封装一个基类
    这里我使用的kotlin,如果想看java的话 可以根据逻辑自己写

  2. 变量的定义 请直接查看注释

 	private var mIsDrug = true //判断是否是点击事件
    private var mCustomIsAttach = true //是否需要自动吸附
    private var mCustomIsDrag = true  // 是否可以拖拽

    private var mLastRawX = 0f //最终位置
    private var mLastRawY = 0f //最终位置
    private var mRootWindowMeasuredWidth = 0 //父布局的宽度
    private var mRootWindowMeasuredHeight = 0 //父布局的高度
    private var mRootTopY = 0 //父布局的顶部
    //用来规避的View 位置
    private val rectF: RectF = RectF(0f, 0f, 0f, 0f) //这里直接创建对象 后面进行内部赋值操作
  1. 最关键的一点 我们要阻止事件的分发
	 override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        super.dispatchTouchEvent(event)
        return true
    }
  1. 设置我们所需要的规避View的坐标(矩形坐标),也就是View的上下左右四个边,也可以通过XY算
	fun setSkipViewRectF(viewRectF: RectF) {
        this.rectF.bottom = viewRectF.bottom
        this.rectF.top = viewRectF.top
        this.rectF.left = viewRectF.left
        this.rectF.right = viewRectF.right
    }
  1. 接下来就是整个代码的灵魂部分了 也是喜闻乐见的重写我们的OnTouchEvent()
 override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (mCustomIsDrag) {
            val mRawX = event?.rawX
            val mRawY = event?.rawY
            when (event?.action) {
                MotionEvent.ACTION_DOWN -> {
                    mIsDrug = false
                    mLastRawX = mRawX!!
                    mLastRawY = mRawY!!
                    val viewGroup = parent as ViewGroup?
                    if (viewGroup != null) {
                        val location = IntArray(2)
                        viewGroup.getLocationInWindow(location)
                        mRootWindowMeasuredHeight = viewGroup.measuredHeight
                        mRootWindowMeasuredWidth = viewGroup.measuredWidth
                        mRootTopY = location[1]
                    }
                }
                MotionEvent.ACTION_MOVE -> {
                    if (mRawX!! >= 0 && mRawX <= mRootWindowMeasuredWidth && mRawY!! >= mRootTopY && mRawY <= (mRootWindowMeasuredHeight + mRootTopY)) {
                        //手指X轴的滑动距离
                        val changeX = mRawX - mLastRawX;
                        //手指Y轴的滑动距离
                        val changeY = mRawY - mLastRawY;
                        //判断是否为拖动操作
                        if (!mIsDrug) {
                            mIsDrug =
                                sqrt(changeX * changeX + changeY * changeY) >= 2
                        }
                        //获取手指按下的距离与控件本身X轴的距离
                        val ownX = x
                        //获取手指按下的距离与控件本身Y轴的距离
                        val ownY = y
                        //理论中X轴拖动的距离
                        var endX = ownX + changeX
                        //理论中Y轴拖动的距离
                        var endY = ownY + changeY
                        //X轴可以拖动的最大距离
                        val maxX = mRootWindowMeasuredWidth - width.toFloat()
                        //Y轴可以拖动的最大距离
                        val maxY = mRootWindowMeasuredHeight - height.toFloat()
                        //X轴边界限制
                        endX = if (endX < 0f) {
                            0f
                        } else {
                            endX.coerceAtMost(maxX)
                        }
                        //Y轴边界限制
                        endY = if (endY < 0f) {
                            0f
                        } else {
                            endY.coerceAtMost(maxY)
                        }
                        //开始移动
                        x = endX
                        y = endY
                        //记录位置
                        mLastRawX = mRawX
                        mLastRawY = mRawY
                    }
                }
                MotionEvent.ACTION_UP -> {
                    if (mCustomIsAttach) {
                        //判断是否为点击事件
                        if (mIsDrug) {
                            val center = (mRootWindowMeasuredWidth shr 1).toFloat()
                            //自动贴边
                            if (mLastRawX <= center) {
                                mLastRawX = 0f
                                animate()
                                    .setInterpolator(BounceInterpolator())
                                    .setDuration(1500)
                                    .x(mLastRawX)
                                    .start()
                            } else {
                                mLastRawX = (mRootWindowMeasuredWidth - width).toFloat()
                                animate()
                                    .setInterpolator(BounceInterpolator())
                                    .setDuration(1500)
                                    .x(mLastRawX)
                                    .start()
                            }
                            //这里是因为我所做的跳过的view是固定右边的 而且自动吸边 所以判断的是上面的mLastRawX
                            if (mLastRawX != 0f) {
                            //获取View的Y中线
                                val y = y + measuredHeight / 2
                               
                                if (y >= rectF.top && y < rectF.bottom) {
                                    animate()
                                        .setInterpolator(BounceInterpolator())
                                        .setDuration(1500)
                                        .y(rectF.top - height)
                                        .start()
                                }
                            }
                        } else {
                            //这里可以处理点击事件
                        }
                    }

                }
            }
        }
        return if (mIsDrug) {
            mIsDrug
        } else {
            super.onTouchEvent(event)
        }

    }

注释大部分代码都给予了说明,这里可能有人不知道怎么实现的自动贴边,这里其实是用了属性动画,可以直接设置View移动到指定的坐标,而不是移动了多少。

  1. 规避某一个View,自动去它的上方(这里可以在代码里自己算,我这里只写了在右侧的上方)
                            if (mLastRawX != 0f) {
                                val y = y + measuredHeight / 2
                                if (y >= rectF.top && y < rectF.bottom) {
                                    animate()
                                        .setInterpolator(BounceInterpolator())
                                        .setDuration(1500)
                                        .y(rectF.top - height)
                                        .start()
                                }
                            }

2.使用教程

		//设置规避的view坐标 主要 请务必在view完全绘制完成后调用 不然会拿不到坐标 常用方法是使用View.post(R r);
        //这里我用了kotlin-android-extensions 这个就是id可以直接用
        //这里如果看不懂 emm 就是kt的语法糖
        skipView.post {
            moveView.setSkipViewRectF(
                //这里创建矩形对象 然后把四个边传入进去 这里我是直接算的 当然也可以直接获得
                RectF(
                    skipView.x,
                    skipView.y,
                    skipView.x + skipView.measuredWidth,
                    skipView.y + skipView.measuredHeight
                )
            )
        }

注意事项

请务必保证View在一个ViewGroup里面,如果没办法保证,可以运用屏幕坐标来实现。
请务必在View完成绘制并准备好了之后去获取坐标,不然有极大的可能是空的。

参考:_____
代码:GitHub

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-13 11:33:29  更:2021-10-13 11:34:23 
 
开发: 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年11日历 -2024/11/23 23:39:41-

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