Android 可拖拽的View,限制在父布局中随意拖拽;拖拽结束后可左右吸边;
实现方法一:自定义View
可随意拖动拖拽的View,限制拖动范围是父布局中;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.ImageView;public class DragActionButton extends ImageView {private int parentHeight;private int parentWidth;private int lastX;private int lastY;private ViewGroup parent;public DragActionButton(Context context) {super(context);}public DragActionButton(Context context, AttributeSet attrs) {super(context, attrs);}public DragActionButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@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:getParent().requestDisallowInterceptTouchEvent(true);lastX = rawX;lastY = rawY;if (getParent() != null) {parent = (ViewGroup) getParent();parentHeight = parent.getHeight();parentWidth = parent.getWidth();}break;case MotionEvent.ACTION_MOVE:if (parentHeight <= 0.2 || parentWidth <= 0.2) {break;}int dx = rawX - lastX;int dy = rawY - lastY;//这里修复一些华为手机无法触发点击事件int distance = (int) Math.sqrt(dx * dx + dy * dy);if (distance == 0) {break;}float x = getX() + dx;float y = getY() + dy;//检测是否到达边缘 左上右下x = x < 0 ? 0 : x + getWidth() > parentWidth ? parentWidth - getWidth() : x;y = y < 0 ? 0 : y + getHeight() > parentHeight ? parentHeight - getHeight() : y;setX(x);setY(y);lastX = rawX;lastY = rawY;Log.i("ACTION_MOVE", "getX=" + getX() + ";getY=" + getY() + ";parentWidth=" + parentWidth+ ";parentHeight=" + parentHeight);break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:this.setAlpha(1.0f);Log.i("ACTION_UP", "getX=" + getX() + ";getY=" + getY());break;}return true;}}
下面是可以左右吸边的效果;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.Toast;import androidx.annotation.Nullable;public class DragFloatActionButton extends ImageView {private int parentHeight;private int parentWidth;Handler handler = new Handler();Runnable runnable = new Runnable() {@Overridepublic void run() {setAlpha(0.3f);}};private int lastX;private int lastY;private ViewGroup parent;public DragFloatActionButton(Context context) {super(context);}public DragFloatActionButton(Context context, AttributeSet attrs) {super(context, attrs);}public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}private int downX;private int downY;private long downTime;@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:this.setAlpha(0.9f);getParent().requestDisallowInterceptTouchEvent(true);lastX = rawX;lastY = rawY;downX = rawX;downY = rawY;downTime = System.currentTimeMillis();if (getParent() != null) {parent = (ViewGroup) getParent();parentHeight = parent.getHeight();parentWidth = parent.getWidth();}break;case MotionEvent.ACTION_MOVE:if (parentHeight <= 0.2 || parentWidth <= 0.2) {break;}this.setAlpha(0.9f);int dx = rawX - lastX;int dy = rawY - lastY;//这里修复一些华为手机无法触发点击事件int distance = (int) Math.sqrt(dx * dx + dy * dy);if (distance == 0) {break;}float x = getX() + dx;float y = getY() + dy;//检测是否到达边缘 左上右下x = x < 0 ? 0 : x + getWidth() > parentWidth ? parentWidth - getWidth() : x;y = y < 0 ? 0 : y + getHeight() > parentHeight ? parentHeight - getHeight() : y;setX(x);setY(y);lastX = rawX;lastY = rawY;Log.i("ACTION_MOVE", "getX=" + getX() + ";getY=" + getY() + ";parentWidth=" + parentWidth+ ";parentHeight=" + parentHeight);break;case MotionEvent.ACTION_UP:moveHide(rawX);if(onClickListener != null&& Math.abs(downX - rawX) < 10&& Math.abs(downY - rawY) < 10&& System.currentTimeMillis() - downTime < 1000){Log.i("ACTION_UP", "触发点击事件 ");onClickListener.onClick(this);}break;}return true;}OnClickListener onClickListener;@Overridepublic void setOnClickListener(@Nullable OnClickListener l) {onClickListener = l;}private void moveHide(int rawX) {if (rawX >= parentWidth / 2) {//靠右吸附animate().setInterpolator(new DecelerateInterpolator()).setDuration(500).xBy(parentWidth - getWidth() - getX()).start();myRunable();} else {//靠左吸附ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);oa.setInterpolator(new DecelerateInterpolator());oa.setDuration(500);oa.start();myRunable();}}private void myRunable() {handler.removeCallbacks(runnable);handler.postDelayed(runnable, 2000);}
实现方法二:自定义ViewGroup
使用ViewDragHelper实现:
ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to drag and reposition views within their parent ViewGroup.
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;import androidx.customview.widget.ViewDragHelper;public class DragViewGroup extends RelativeLayout {private ViewDragHelper mDragger;private View mDragView;public DragViewGroup(Context context, AttributeSet attrs) {super(context, attrs);this.setGravity(Gravity.CENTER);mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {@Overridepublic boolean tryCaptureView(View child, int pointerId) {return true;}@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {final int leftBound = getPaddingLeft();final int rightBound = getWidth() - mDragView.getWidth();final int newLeft = Math.min(Math.max(left, leftBound), rightBound);return newLeft;}@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {final int topBound = getPaddingTop();final int bottomBound = getHeight() - mDragView.getHeight();final int newTop = Math.min(Math.max(top, topBound), bottomBound);return newTop;}//手指释放的时候回调@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {Log.i("onViewReleased", "view: x :"+mDragView.getX() +"y:"+mDragView.getY()+"\nviewgroup: w: "+getWidth() + "h : "+getHeight());}});}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {return mDragger.shouldInterceptTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {mDragger.processTouchEvent(event);return true;}@Overrideprotected void onFinishInflate() {super.onFinishInflate();mDragView = getChildAt(0);}
}
相关文章:
Android 可拖拽的View,限制在父布局中随意拖拽;拖拽结束后可左右吸边;
实现方法一:自定义View 可随意拖动拖拽的View,限制拖动范围是父布局中; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.ViewGroup; …...
逐步更新动画混合参数(Blend)使其平滑地过渡到目标值
1.具体实现 逐步更新一个动画混合参数(Blend),使其平滑地过渡到目标值,可以实现角色动作的平滑过渡,比如从走路过渡到跑步。 private float currentBleng;private float targetBlend;public float accelerSpeed 5;//…...
【多模态/CV】图像数据增强数据分析和处理
note 多模态大模型训练前,图片数据处理的常见操作:分辨率调整、网格畸变、水平翻转、分辨率调整、随机crop、换颜色、多张图片拼接、相似图片检测并去重等 一、分辨率调整 from PIL import Image def resize_image(original_image_path, save_image_p…...
代码随想录——修建二叉搜素树(Leetcode669)
题目链接 递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …...
EasyExcel导出多个sheet封装
导出多个sheet 在需求中,会有需要导出多种sheet的情况,那么这里使用easyexcel进行整合 步骤 1、导入依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><d…...
【Python错误】:AttributeError: ‘generator‘ object has no attribute ‘next‘解决办法
【Python错误】:AttributeError: ‘generator’ object has no attribute next’解决办法 在Python中,生成器是一种使用yield语句的特殊迭代器,它允许你在函数中产生一个值序列,而无需一次性创建并返回整个列表。然而,…...
如何配置Feign以实现服务调试
1、引入依赖 在项目中,需要引入Spring Cloud OpenFeign的依赖。这通常是通过在pom.xml文件中添加相应的Maven依赖来完成的。例如: <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starte…...
pc之间的相互通信详解
如图,实现两台pc之间的相互通信 1.pc1和pc2之间如何进行通讯。 2.pc有mac和ip,首先pc1需要向sw1发送广播,sw1查询mac地址表,向router发送广播,router不接受广播,router的每个接口都有ip和mac,…...
Mongodb中字段的删除
学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第61篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。 本篇文章,探讨UPDATE中的操作符$unset。Mongodb数据插入后,开发人员使用$u…...
TP8 PHP 动态变量调用 (new $class())->$action($data)
动态: $class \app\table\model\Log; $action DataSave; $data [...]; // 假设这是你要保存的数据//class_exists和method_exists的检查,这段代码能够在尝试实例化类或调用方法之前,先验证类是否存在以及该类中是否存在指定的方法。如果类…...
理解JVM内存模型与Java内存模型(JMM)
理解JVM内存模型与Java内存模型(JMM) 在Java程序的运行过程中,内存管理和线程的同步是两个重要的概念。本文将深入探讨JVM内存模型(Java Virtual Machine Memory Model)和JMM(Java Memory Model࿰…...
鸿蒙OS初识
学习官网:https://www.harmonyos.com/cn/develop 准备 注册,安装软件(node:12, DevEco Studio): https://developer.harmonyos.com/cn/docs/documentation/doc-guides/software_install-0000001053582415#ZH-CN_TOP…...
发布自己的 npm 插件包:步骤与最佳实践
在 Node.js 的生态系统中,npm(Node Package Manager)是一个不可或缺的组成部分。npm 允许开发者创建、共享和使用各种库和插件。如果你有自己的 Node.js 插件或库,并且希望与全世界的其他开发者共享,那么发布到 npm 是…...
BubbleML: A Multiphase Multiphysics Dataset and Benchmarks for Machine Learning
我们使用以下六个分类标准: 研究方法: 这个标准根据如何收集和分析数据来区分研究方法。 实验研究,如参考文献[64]中的研究,涉及在受控环境中研究人员操纵变量并观察结果的物理实验。这种方法对于收集真实世界的数据很有价值,但可能成本高且耗时。模拟研究利用计算模型来模…...
vscode+latex设置跳转快捷键
安装参考 https://blog.csdn.net/Hacker_MAI/article/details/130334821 设置默认recipe ctrl P 打开设置,搜索recipe 也可以点这里看看有哪些配置 2 设置跳转快捷键...
PHP序列化、反序列化
目录 一、PHP序列化:serialize() 1.对象序列化 2.pop链序列化 3.数组序列化 二、反序列化:unserialize() 三、魔术方法 四、NSSCTF相关简单题目 1.[SWPUCTF 2021 新生赛]ez_unserialize 2.[SWPUCTF 2021 新生赛]no_wakeup 学习参考࿱…...
websocket链接携带参数
前端创建链接时官方提供的构造函数 var aWebSocket new WebSocket(url, [protocols]); url:要连接的URL;这应该是WebSocket服务器将响应的URL。 protocols:可选;一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定…...
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:初步了解 list 🌹🌹期待您的关注 🌹🌹 ❀STL之list 📒1. list…...
技术管理之巅—如何从零打造高质效互联网技术团队阅读体验
技术管理之巅—如何从零打造高质效互联网技术团队 《技术管理之巅:如何从零打造高质效互联网技术团队》是黄哲铿所著的一本书,致力于帮助技术管理者从零开始打造高效的互联网技术团队。该书分为多个章节,分别探讨了从团队文化建设到技术架构…...
机器学习与数据挖掘知识点总结(一)
简介:随着人工智能(AI)蓬勃发展,也有越来越多的人涌入到这一行业。下面简单介绍一下机器学习的各大领域,机器学习包含深度学习以及强化学习,在本节的机器学习中主要阐述一下机器学习的线性回归逻辑回归&…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
