Android控件全解手册 - 任意View缩放平移工具-源码

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总
游戏脚本-辅助自动化Android控件全解手册再战Android系列
Scratch编程案例软考全系列Unity3D学习专栏
蓝桥系列ChatGPT和AIGC

👉关于作者

专注于Android/Unity和各种游戏开发技巧,以及各种资源分享(网站、工具、素材、源码、游戏等)
有什么需要欢迎底部卡片私我,交流让学习不再孤单

在这里插入图片描述

👉实践过程

GestureViewBinder

public class GestureViewBinder {private ScaleGestureBinder scaleGestureBinder;private ScrollGestureBinder scrollGestureBinder;private ScaleGestureListener scaleGestureListener;private ScrollGestureListener scrollGestureListener;private View targetView;private ViewGroup viewGroup;private boolean isScaleEnd = true;private OnScaleListener onScaleListener;private boolean isFullGroup = false;public static GestureViewBinder bind(Context context, ViewGroup viewGroup, View targetView) {return new GestureViewBinder(context, viewGroup, targetView);}private GestureViewBinder(Context context, ViewGroup viewGroup, View targetView) {this.targetView = targetView;this.viewGroup = viewGroup;scaleGestureListener = new ScaleGestureListener(targetView, viewGroup);scrollGestureListener = new ScrollGestureListener(targetView, viewGroup);scaleGestureBinder = new ScaleGestureBinder(context, scaleGestureListener);scrollGestureBinder = new ScrollGestureBinder(context, scrollGestureListener);targetView.setClickable(false);viewGroup.setOnTouchListener(new View.OnTouchListener() {@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouch(View v, MotionEvent event) {if (event.getPointerCount() == 1 && isScaleEnd) {return scrollGestureBinder.onTouchEvent(event);} else if (event.getPointerCount() == 2 || !isScaleEnd) {isScaleEnd = event.getAction() == MotionEvent.ACTION_UP;if (isScaleEnd) {scaleGestureListener.onActionUp();}scrollGestureListener.setScale(scaleGestureListener.getScale());if (onScaleListener != null) {onScaleListener.onScale(scaleGestureListener.getScale());}return scaleGestureBinder.onTouchEvent(event);}return false;}});}private void fullGroup() {targetView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {@Overridepublic boolean onPreDraw() {targetView.getViewTreeObserver().removeOnPreDrawListener(this);float viewWidth = targetView.getWidth();float viewHeight = targetView.getHeight();float groupWidth = viewGroup.getWidth();float groupHeight = viewGroup.getHeight();ViewGroup.LayoutParams layoutParams = targetView.getLayoutParams();float widthFactor = groupWidth / viewWidth;float heightFactor = groupHeight / viewHeight;if (viewWidth < groupWidth && widthFactor * viewHeight <= groupHeight) {layoutParams.width = (int) groupWidth;layoutParams.height = (int) (widthFactor * viewHeight);} else if (viewHeight < groupHeight && heightFactor * viewWidth <= groupWidth) {layoutParams.height = (int) groupHeight;layoutParams.width = (int) (heightFactor * viewWidth);}targetView.setLayoutParams(layoutParams);return true;}});}public boolean isFullGroup() {return isFullGroup;}public void setFullGroup(boolean fullGroup) {isFullGroup = fullGroup;scaleGestureListener.setFullGroup(fullGroup);scrollGestureListener.setFullGroup(fullGroup);fullGroup();}public void setOnScaleListener(OnScaleListener onScaleListener) {this.onScaleListener = onScaleListener;}public interface OnScaleListener {void onScale(float scale);}
}

ScaleGestureBinder

public class ScaleGestureBinder extends ScaleGestureDetector {ScaleGestureBinder(Context context, ScaleGestureListener scaleGestureListener) {super(context, scaleGestureListener);}@Overridepublic boolean onTouchEvent(MotionEvent event) {return super.onTouchEvent(event);}}

ScaleGestureListener

public class ScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener/*, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener */ {private View targetView;private float scale = 1;private float scaleTemp = 1;private boolean isFullGroup = false;ScaleGestureListener(View targetView, ViewGroup viewGroup) {this.targetView = targetView;}@Overridepublic boolean onScale(ScaleGestureDetector detector) {scale = scaleTemp * detector.getScaleFactor();targetView.setScaleX(scale);targetView.setScaleY(scale);return false;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {scaleTemp = scale;}float getScale() {return scale;}public boolean isFullGroup() {return isFullGroup;}void setFullGroup(boolean fullGroup) {isFullGroup = fullGroup;}void onActionUp() {if (isFullGroup && scaleTemp < 1) {scale = 1;targetView.setScaleX(scale);targetView.setScaleY(scale);scaleTemp = scale;}}
}

ScrollGestureBinder

class ScrollGestureBinder extends GestureDetector {ScrollGestureBinder(Context context, ScrollGestureListener scrollGestureListener) {super(context, scrollGestureListener);}
}

ScrollGestureListener

public class ScrollGestureListener extends GestureDetector.SimpleOnGestureListener {private float scale = 1;private View targetView;private ViewGroup viewGroup;private float distanceXTemp = 0;private float distanceYTemp = 0;private float viewWidthReal = 0;private float viewHeightReal = 0;private float viewWidthRealTemp = 0;private float viewHeightRealTemp = 0;private boolean isCalculate = false;private int viewWidthNormal = 0;private int viewHeightNormal = 0;private int groupWidth = 0;private int groupHeight = 0;private float maxTranslationLeft = 0;private float maxTranslationTop = 0;private float maxTranslationRight = 0;private float maxTranslationBottom = 0;private boolean isFullGroup = false;ScrollGestureListener(View targetView, ViewGroup viewGroup) {this.targetView = targetView;this.viewGroup = viewGroup;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {distanceX = -distanceX;distanceY = -distanceY;if (isFullGroup || scale > 1) {if (viewWidthReal > groupWidth) {translationXOnScrollEvent(distanceX);}if (viewHeightReal > groupHeight) {translationYOnScrollEvent(distanceY);}} else {translationXOnScrollEvent(distanceX);translationYOnScrollEvent(distanceY);}return super.onScroll(e1, e2, distanceX, distanceY);}private void translationXOnScrollEvent(float distanceX) {//最大移动距离全部为正数,所以需要通过判断distanceX的正负,来判断是向左移动还是向右移动,// 然后通过取distanceX的绝对值来和相应移动方向的最大移动距离比较if ((distanceX < 0 && Math.abs(distanceXTemp + distanceX) < maxTranslationLeft)|| (distanceX > 0 && distanceXTemp + distanceX < maxTranslationRight)) {distanceXTemp += distanceX;targetView.setTranslationX(distanceXTemp);//如果超出边界,就移动到最大距离,防止边界有剩余量} else if ((distanceX < 0 && Math.abs(distanceXTemp + distanceX) > maxTranslationLeft)) {distanceXTemp = -maxTranslationLeft;targetView.setTranslationX(-maxTranslationLeft);} else if ((distanceX > 0 && distanceXTemp + distanceX > maxTranslationRight)) {distanceXTemp = maxTranslationRight;targetView.setTranslationX(maxTranslationRight);}}private void translationYOnScrollEvent(float distanceY) {if ((distanceY < 0 && Math.abs(distanceYTemp + distanceY) < maxTranslationTop)|| (distanceY > 0 && distanceYTemp + distanceY < maxTranslationBottom)) {distanceYTemp += distanceY;targetView.setTranslationY(distanceYTemp);//如果超出边界,就移动到最大距离,防止边界有剩余量} else if ((distanceY < 0 && Math.abs(distanceYTemp + distanceY) > maxTranslationTop)) {distanceYTemp = -maxTranslationTop;targetView.setTranslationY(-maxTranslationTop);} else if ((distanceY > 0 && distanceYTemp + distanceY > maxTranslationBottom)) {distanceYTemp = maxTranslationBottom;targetView.setTranslationY(maxTranslationBottom);}}@Overridepublic boolean onDown(MotionEvent e) {//计算能移动的最大距离if (!isCalculate) {isCalculate = true;maxTranslationLeft = targetView.getLeft();maxTranslationTop = targetView.getTop();maxTranslationRight = viewGroup.getWidth() - targetView.getRight();maxTranslationBottom = viewGroup.getHeight() - targetView.getBottom();viewWidthNormal = targetView.getWidth();viewHeightNormal = targetView.getHeight();viewWidthRealTemp = viewWidthNormal;viewHeightRealTemp = viewHeightNormal;viewWidthReal = viewWidthNormal;viewHeightReal = viewHeightNormal;groupWidth = viewGroup.getWidth();groupHeight = viewGroup.getHeight();}return true;}void setScale(float scale) {viewWidthReal = viewWidthNormal * scale;viewHeightReal = viewHeightNormal * scale;//如果view比group小if (viewWidthReal < groupWidth) {if (isFullGroup) {distanceXTemp = 0;targetView.setTranslationX(0);}maxTranslationLeft = targetView.getLeft() - (viewWidthReal - viewWidthNormal) / 2;maxTranslationRight = (viewGroup.getWidth() - targetView.getRight()) - (viewWidthReal - viewWidthNormal) / 2;//如果移动距离超过最大可移动距离if (scale > this.scale && distanceXTemp < 0 && -distanceXTemp > maxTranslationLeft) {float translate = (viewWidthReal - viewWidthRealTemp) / 2;targetView.setTranslationX(targetView.getTranslationX() + translate);distanceXTemp = distanceXTemp + translate;} else if (scale > this.scale && distanceXTemp > 0 && distanceXTemp > maxTranslationRight) {float translate = (viewWidthReal - viewWidthRealTemp) / 2;targetView.setTranslationX(targetView.getTranslationX() - translate);distanceXTemp = distanceXTemp - translate;}} else {maxTranslationLeft = (viewWidthReal - viewWidthNormal) / 2 - (viewGroup.getWidth() - targetView.getRight());maxTranslationRight = (viewWidthReal - viewWidthNormal) / 2 - targetView.getLeft();if (scale < this.scale && distanceXTemp < 0 && -distanceXTemp > maxTranslationLeft) {float translate = (viewWidthRealTemp - viewWidthReal) / 2;targetView.setTranslationX(targetView.getTranslationX() + translate);distanceXTemp = distanceXTemp + translate;} else if (scale < this.scale && distanceXTemp > 0 && distanceXTemp > maxTranslationRight) {float translate = (viewWidthRealTemp - viewWidthReal) / 2;targetView.setTranslationX(targetView.getTranslationX() - translate);distanceXTemp = distanceXTemp - translate;}}if (viewHeightReal < groupHeight) {maxTranslationTop = targetView.getTop() - (viewHeightReal - viewHeightNormal) / 2;maxTranslationBottom = (viewGroup.getHeight() - targetView.getBottom()) - (viewHeightReal - viewHeightNormal) / 2;if (isFullGroup) {distanceYTemp = 0;targetView.setTranslationY(0);}//如果移动距离超过最大可移动距离if (scale > this.scale && distanceYTemp < 0 && -distanceYTemp > maxTranslationTop) {float translate = (viewHeightReal - viewHeightRealTemp) / 2;targetView.setTranslationY(targetView.getTranslationY() + translate);distanceYTemp = distanceYTemp + translate;} else if (scale > this.scale && distanceYTemp > 0 && distanceYTemp > maxTranslationBottom) {float translate = (viewHeightReal - viewHeightRealTemp) / 2;targetView.setTranslationY(targetView.getTranslationY() - translate);distanceYTemp = distanceYTemp - translate;}} else {maxTranslationTop = (viewHeightReal - viewHeightNormal) / 2 - (viewGroup.getHeight() - targetView.getBottom());maxTranslationBottom = (viewHeightReal - viewHeightNormal) / 2 - targetView.getTop();if (scale < this.scale && distanceYTemp < 0 && -distanceYTemp > maxTranslationTop) {float translate = (viewHeightRealTemp - viewHeightReal) / 2;targetView.setTranslationY(targetView.getTranslationY() + translate);distanceYTemp = distanceYTemp + translate;} else if (scale < this.scale && distanceYTemp > 0 && distanceYTemp > maxTranslationBottom) {float translate = (viewHeightRealTemp - viewHeightReal) / 2;targetView.setTranslationY(targetView.getTranslationY() - translate);distanceYTemp = distanceYTemp - translate;}}viewWidthRealTemp = viewWidthReal;viewHeightRealTemp = viewHeightReal;this.scale = scale;}@Overridepublic boolean onSingleTapUp(MotionEvent e) {float left = viewWidthReal > groupWidth ? 0 : (targetView.getLeft() - ((viewWidthReal - viewWidthNormal) / 2));float top = viewHeightReal > groupHeight ? 0 : (targetView.getTop() - ((viewHeightReal - viewHeightNormal) / 2));float right = viewWidthReal > groupWidth ? groupWidth : viewGroup.getWidth() - ((viewGroup.getWidth() - targetView.getRight()) - (viewWidthReal - viewWidthNormal) / 2);float bottom = viewHeightReal > groupHeight ? groupHeight : viewGroup.getHeight() - ((viewGroup.getHeight() - targetView.getBottom()) - (viewHeightReal - viewHeightNormal) / 2);RectF rectF = new RectF(left, top, right, bottom);if (rectF.contains(e.getX(), e.getY())) {targetView.performClick();}return super.onSingleTapUp(e);}public boolean isFullGroup() {return isFullGroup;}void setFullGroup(boolean fullGroup) {isFullGroup = fullGroup;}
}

👉其他

📢作者:小空和小芝中的小空
📢转载说明-务必注明来源:https://zhima.blog.csdn.net/
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

温馨提示点击下方卡片获取更多意想不到的资源。
空名先生

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/180462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

竞赛选题 题目:基于机器视觉的图像矫正 (以车牌识别为例) - 图像畸变校正

文章目录 0 简介1 思路简介1.1 车牌定位1.2 畸变校正 2 代码实现2.1 车牌定位2.1.1 通过颜色特征选定可疑区域2.1.2 寻找车牌外围轮廓2.1.3 车牌区域定位 2.2 畸变校正2.2.1 畸变后车牌顶点定位2.2.2 校正 7 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享…

yolov8-pose姿势估计,站立识别

系列文章目录 基于yolov8-pose的姿势估计模式,实现站姿,坐姿,伏案睡姿识别,姿态动作识别接口逻辑作参考。本文以学习交流,分享,欢迎留言讨论优化。 yoloPose-姿势动作识别 系列文章目录前言一、环境安装二、使用yolov8-pose1.导入模型,预测图像三.姿势动作识别之站立总…

人工智能_机器学习053_支持向量机SVM目标函数推导_SVM条件_公式推导过程---人工智能工作笔记0093

然后我们再来看一下支持向量机SVM的公式推导情况 来看一下支持向量机是如何把现实问题转换成数学问题的. 首先我们来看这里的方程比如说,中间的黑线我们叫做l2 那么上边界线我们叫l1 下边界线叫做l3 如果我们假设l2的方程是上面这个方程WT.x+b = 0 那么这里 我们只要确定w和…

<Linux> 文件理解与操作

目录 前言&#xff1a; 一、关于文件的预备知识 二、C语言文件操作 1. fope 2. fclose 3. 文件写入 3.1 fprintf 3.2 snprintf 三、系统文件操作 1. open 2. close 3. write 4. read 四、C文件接口与系统文件IO的关系 五、文件描述符 1. 理解文件描述符 2. 文…

一则 MongoDB 副本集迁移实操案例

文中详细阐述了通过全量 增量 Oplog 的迁移方式&#xff0c;完成一套副本集 MongoDB 迁移的全过程。 作者&#xff1a;张然&#xff0c;DBA 数据库技术爱好者~ 爱可生开源社区出品&#xff0c;原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。 本文约 900…

python炒股自动化(1),量化交易接口区别

要实现股票量化程序化自动化&#xff0c;就需要券商提供的API接口&#xff0c;重点是个人账户小散户可以申请开通&#xff0c;上手要简单&#xff0c;接口要足够全面&#xff0c;功能完善&#xff0c;首先&#xff0c;第一步就是要找对渠道和方法&#xff0c;这里我们不讨论量化…

linux 内核等待队列

等待队列在Linux内核中用来阻塞或唤醒一个进程&#xff0c;也可以用来同步对系统资源的访问&#xff0c;还可以实现延迟功能 在软件开发中任务经常由于某种条件没有得到满足而不得不进入睡眠状态&#xff0c;然后等待条件得到满足的时候再继续运行&#xff0c;进入运行状态。这…

网络安全--基于Kali的网络扫描基础技术

文章目录 1. 标准ICMP扫描1.1使用Ping命令1.1.1格式1.1.2实战 1.2使用Nmap工具1.2.1格式1.2.2实战1.2.2.1主机在线1.2.2.2主机不在线 1.3使用Fping命令1.3.1格式1.3.2实战 2. 时间戳查询扫描2.1格式2.2实战 3. 地址掩码查询扫描3.1格式3.2实战 2. TCP扫描2.1TCP工作机制2.2TCP …

位运算总结

文章目录 &#x1f348;1. 基础位运算&#x1f34c;2. 给一个数n&#xff0c;确定它的二进制表示中的第x位是0还是1&#x1f34f;3. 将一个数n的二进制表示的第x位修改成1&#x1f353;4. 将一个数的n的二进制表示的第x位修改成0&#x1f954;5. 位图的思想&#x1fad2;6. 提前…

医保移动支付程序开发

作为公司最苦命的开发&#xff0c;年初接到任务开发医保移动支付程序&#xff08;微信小程序和支付宝小程序&#xff09;&#xff0c;为医疗机构提供线上医保结算。好家伙&#xff0c;我一看解压后资料大于一个G&#xff0c;内心无比的惊慌。 一、技术流程图 图太大了显示不全需…

0-1背包的初始化问题

题目链接 这道题的状态转移方程比较易于确定。dp[i][j]表示能放前i个物品的情况下&#xff0c;容量为j时能放物品的数量&#xff08;这道题歌曲数量对应物品数量&#xff0c;容量对应时间&#xff09;。 技巧&#xff08;收获&#xff09; 二维dp数组可以视情况优化为一维dp数组…

Linux——vim编辑文件时——.swp文件解决方案

test.cpp样例 当我们vim test.cpp进入编辑文件。 却忘记了保存退出 再次进入就会出现一下画面 当你摁下Enter键位 出现以下几个选项 O——是只读不写 E——是正常打开文件但不会载入磁盘内容 R——覆盖——是加载存储磁盘的文件(当我们忘记保存时&#xff0c;系统会自动帮我…

事件代理?

1.什么是事件代理&#xff1f; 事件代理也叫事件委托&#xff0c;只指定一个事件处理程序&#xff0c;就可以管理某一类型得事件。 可以简单理解为&#xff0c;事件代理就是将本应该绑定子元素事件绑定给父元素代理。它的优点就是&#xff1a;减少事件得执行&#xff0c;减少浏…

CentOS 7 部署 MariaDB 的 2 种方法

有两种安装 MariaDB 服务器的方法。您可以安装 CentOS 7 存储库中可用的默认版本&#xff0c;也可以通过手动添加 MariaDB 存储库来安装最新版本。 如果安装过MariaDB或MySQL&#xff0c;使用以下命令彻底删除它们: yum remove mariadb* yum remove mysql* 方法一: 使用 Yum…

Make Pixels Dance: High-Dynamic Video Generation论文解析

高动态视频生成的新进展 Make Pixels Dance: High-Dynamic Video Generation高动态视频生成的新进展前言视频生成模式摘要论文十问实验数据集定量评估指标消融研究 训练和推理技巧训练技术推理技术 更多的应用 Make Pixels Dance: High-Dynamic Video Generation 高动态视频生…

VBA技术资料MF87:创建固定顺序名称的一组文件夹

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

gRPC Java、Go、PHP使用例子

文章目录 1、Protocol Buffers定义接口1.1、编写接口服务1.2、Protobuf基础数据类型 2、服务器端实现2.1、生成gRPC服务类2.2、Java服务器端实现 3、java、go、php客户端实现3.1、Java客户端实现3.2、Go客户端实现3.3、PHP客户端实现 4、运行效果 本文例子是在Window平台测试&a…

Unity UGUI图片锯齿严重怎么解决

在开发的时候&#xff0c;发现图片锯齿严重&#xff0c;打包到移动端或者在编辑器都这样&#xff0c;如下图 原因&#xff1a; 查了一些资料&#xff0c;找到了原因如下&#xff1a;关于为什么会发生这种情况&#xff1a;看起来你的源资源比你在屏幕上显示的大小大得多。所以当…

深入浅出 Vue 中的插槽 slot

深入浅出 Vue 中的插槽 slot start 最近被问到好几次 Vue 中的插槽相关知识&#xff0c;掌握的还是有些不全面。抱着重新学习的心态&#xff0c;写这篇博客。首先对基础知识做一个回顾&#xff0c;然后再对源码实现做一个学习。作者&#xff1a;番茄编写时间&#xff1a;2023…

STM32_10(I2C)

I2C通信 I2C&#xff08;Inter IC Bus&#xff09;是由Philips公司开发的一种通用数据总线两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff09;、SDA&#xff08;Serial Data&#xff09;同步&#xff0c;半双工带数据应答支持总线挂载多设备&#xff08;一主多从…