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,一经查实,立即删除!

相关文章

详细介绍如何使用 PaddleOCR 进行光学字符识别-(含源码及讲解)

阅读巨大的文档可能会非常累并且非常耗时。您一定见过许多软件或应用程序,只需单击图片即可从文档中获取关键信息。这是通过一种称为光学字符识别 (OCR) 的技术来完成的。光学字符识别是近年来人工智能领域的重点研究之一。光学字符识别是通过理解和分析图像的基本模式来识别图…

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

文章目录 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.导入模型,预测图像三.姿势动作识别之站立总…

unity实时保存对象的位姿,重新运行程序时用最后保存的数据给物体赋值

using UnityEngine; using System.IO; // using System.Xml.Serialization; public class SaveCoordinates : MonoBehaviour {public GameObject MainObject;//读取坐标private float x;private float y;private float z;private Quaternion quaternion;private void Start(){/…

如何使用torchrun启动单机多卡DDP并行训练

如何使用torchrun启动单机多卡DDP并行训练 这是一个最近项目中需要使用的方式&#xff0c;新近的数据集大概在40w的规模&#xff0c;而且载入的原始特征都比较大&#xff08;5&#xff5e;7M&#xff09;&#xff0c;所以准备尝试DistributedDataParallel&#xff1b; 主要目…

Qt 自定义标题栏

在Qt中&#xff0c;如果你想要自定义窗口的标题栏&#xff0c;你可以通过覆盖窗口的windowTitleChanged信号来实现。然而&#xff0c;直接修改Qt的标题栏可能会带来一些问题&#xff0c;因为Qt的设计是尽量使窗口系统的行为标准化。 以下是一个基本的示例&#xff0c;如何在Qt…

Java中的集合

Java中的集合 java.util 包中的集合 Java 集合框架提供了各种集合类&#xff0c;用于存储和管理对象。以下是 Java 集合框架中常见的集合类&#xff1a; List 接口表示一个有序的集合&#xff0c;其中的元素可以重复。List 接口有以下实现类&#xff1a; ArrayList&#xff1…

人工智能_机器学习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. 文…

时延抖动和通信的本质

先从网络时延抖动的根源说起。 信息能否过去取决于信道容量&#xff0c;而信道利用率则取决于编码。这是香农定律决定的。 考虑到主机处理非常快&#xff0c;忽略处理时延&#xff0c;端到端时延就是信息传播时延&#xff0c;但现实中通信信道利用率非常不均匀&#xff0c;统…

一则 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 …

MySQL 索引类型

什么是索引&#xff1f; 索引是一种用于提高数据库查询性能的数据结构。它是在表中一个或多个列上创建的&#xff0c;可以加快对这些列的数据检索速度。 索引的作用是通过创建一个额外的数据结构&#xff0c;使得数据库可以更快地定位和访问数据。当执行查询语句时&#xff0c…

【数据库设计和SQL基础语法】--SQL语言概述--SQL的基本结构和语法规则(一)

一、SQL的基本结构 2.1 SQL语句的组成要素 SQL语句的组成要素 关键字&#xff08;Keywords&#xff09;: 定义&#xff1a;SQL语句的基本操作命令&#xff0c;表示要执行的动作。例子&#xff1a;SELECT、INSERT、UPDATE、DELETE等。 标识符&#xff08;Identifiers&#xf…

位运算总结

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

医疗智能化:人工智能的助力与隐患

文章目录 引言&#xff1a;积极影响风险和挑战 结尾&#xff1a; 引言&#xff1a; 医疗领域正处于人工智能技术革新的前沿。人工智能的涌现为医疗保健带来了前所未有的变革&#xff0c;同时也潜藏着一系列积极影响和潜在挑战。探索人工智能在医疗领域中的影响将有助于我们更深…

医保移动支付程序开发

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

0-1背包的初始化问题

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