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")
            @Override
            public 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() {
                    @Override
                    public 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);
    }

    @Override
    public 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;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        scale = scaleTemp * detector.getScaleFactor();
        targetView.setScaleX(scale);
        targetView.setScaleY(scale);
        return false;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    @Override
    public 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;
    }

    @Override
    public 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);
        }
    }

    @Override
    public 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;
    }

    @Override
    public 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/
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Python入门系列之十一]在windows上安装OpenCV

1-安装OpenCV 如果是python3.7–python3.9(已测试)&#xff0c;直接安装即可 注&#xff1a;conda需要先激活虚拟环境后再安装 pip install opencv-python如果安装速度慢&#xff0c;使用下面的指令&#xff1a; pip install opencv-python -i https://pypi.tuna.tsinghua.e…

【鲁班猫创意大赛2期】基于鲁班猫的幼儿Al监督系统

【鲁班猫创意大赛2期】基于鲁班猫的幼儿Al监督系统 作品介绍 本作品名称为“基于鲁班猫的幼儿 Al 学习助手”&#xff08;系统总体框图如下图&#xff09;&#xff0c;作品应用群体为幼儿群体&#xff0c;主要功能&#xff1a;通过实时坐姿检测&#xff0c;防止坐姿不端正导致…

Linux详解——常用命令(二)

目录 一、常用命令 1.进程相关命令 2.vi命令 3.软件相关命令 RPM命令 YUM命令 4.用户和组相关命令 5.权限相关命令 一、常用命令 1.进程相关命令 # 1.ps 询在当前控制台上运行的进程 ps -aux 说明:查询系统中所有运行的进程&#xff0c;包括后台进程&#xff0c;其…

Git删除临时分支

愿所有美好如期而遇 软件开发过程中&#xff0c;总有功能要添加进来&#xff0c;当我们有一个功能开发了一半的时候&#xff0c;产品经理说这个功能不需要了&#xff0c;尽管很无奈&#xff0c;但还是要删除&#xff0c;我开发到一半的分支如何删除呢&#xff1f; 所以需要使用…

seurat读取不同数据格式以创建Seurat单细胞对象

挖掘GEO公共单细胞数据集时&#xff0c;会遇到常见各种单细胞测序数据格式。现总结如下&#xff0c;方便自己日后调用&#xff0c;以创建Seurat对象 &#xff08;1&#xff09;barcodes.tsv.gz、features.tsv.gz、matrix.mtx.gz &#xff08;2&#xff09;表达矩阵 &#xff08…

春安航运 App Tech Support

春安航运app是一款客户可以实时查看合同进度和自助开票&#xff0c;并且提供航运实用小工具的手机软件。软件的主要功能包括合同查询功能(合同详细&#xff0c;操作船代&#xff0c;分享&#xff0c;合同执行状态&#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…

CI/CD 构建中能保护好 SSHKEY吗?

目录 背景 方案 编码存储 逐行存储 合并存储 打马赛克 结论 背景 使用极狐GitLab CI/CD&#xff0c;在部署方面&#xff0c;主要有两种方式&#xff1a; 部署到K8S集群 Push模式&#xff1a;流水线通过kubectl执行命令部署&#xff0c;这需要把K8S的权限给流水线&#xf…

htop命令中显示相同进程的解决方案

使用 htop 的过程中会发现有很多同样的进程被标注了绿色大量显示。如下图所示。 这使得在大量程序运行时想要找到需要观察的进程变的困难。本文介绍了如何省略这些重复现实的进程。 输入 htop&#xff0c;显示出 htop 界面。按下 F2 键&#xff0c;进入 Setup 模式点击 Displa…

记录Windows下安装redis的过程

开源博客项目Blog支持使用EasyCaching组件操作redis等缓存数据库&#xff0c;在继续学习开源博客项目Blog之前&#xff0c;准备先学习redis和EasyCaching组件的基本用法&#xff0c;本文记录在Windows下安装redis的过程。   虽然redis官网文档写着支持Linux、macOS、Windows等…

Linux的Sysfs 接口

一、sysfs接口 在linux系统中&#xff0c;用户空间访问驱动程序一般是以“设备文件”的方式通过“read/write/ioctl”访问&#xff0c;还有一种方式&#xff0c;可以通过echo的方式来直接控制硬件或者修改驱动&#xff0c;也能为底层驱动提供一个接口便于应用层调用&#xff0c…

Servlet-Vue-JSON交互

Servlet-Vue-JSON交互 统一结果返回 定义 package org.example.result;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;Data NoArgsConstructor AllArgsConstructor public class Result<T> {private Integer code;private St…

Programming Abstractions in C阅读笔记:p202-p234

《Programming Abstractions in C》学习第65天&#xff0c;p202-p234总结。 一、技术总结 完成第五章学习&#xff0c;第五章介绍递归在实际问题中的进一步应用&#xff0c;例如汉诺塔问题&#xff0c;数学中的排列问题&#xff0c;更有难度。使用递归解决问题时有时候需要借…

笔记-PC端wireshark采集FPGA数据的操作

wireshark采集FPGA的数据 目录 一、准备工作二、操作步骤 一、准备工作 1、软件&#xff1a;wireshark 2、平台&#xff1a;PC&#xff08;本人是win11&#xff09;、带有以太网功能的zynq平台 3、网线: 用网线连接zynq板子和PC的以太口端口 二、操作步骤 1、打开任务管理器…

《尚品甄选》:后台系统——权限管理之分类和品牌管理,使用EasyExcel导入导出数据(debug一遍)

文章目录 一、分类管理1.1 表结构介绍1.2 分类列表查询 二、EasyExcel使用2.1 EasyExcel简介2.2 导出功能2.3 导入功能 三、品牌管理3.1 表结构介绍3.2 列表查询3.3 添加品牌3.4 修改品牌3.5 删除品牌 一、分类管理 分类管理就是对商品的分类数据进行维护。 1.1 表结构介绍 分…

Positive Technologies 公司发布了一种保护容器环境的产品 PT Container Security

根据 Positive Technologies 公司的数据&#xff0c;该类产品在俄罗斯的市场容量为 25 亿卢布&#xff0c;据预测&#xff0c;到 2026 年将增长两倍 Positive Technologies 公司正在增加应用安全方面的产品组合。新产品 PT Container Security可在构建、部署和工业运行阶段自动…

【数学】旋转矩阵

参考链接 OpenGL from OpenGL.GL import * from OpenGL.GLUT import * from math import * import numpy as np def draw_axes():glClear(GL_COLOR_BUFFER_BIT)# 绘制坐标轴glColor3f(1.0, 1.0, 1.0) # 设置坐标轴颜色为白色glBegin(GL_LINES)glVertex2f(-1.0, 0.0) # x 轴g…

Dijkstra算法(贪心),Floyd-Warshall算法(动态规划), Bellman-Ford算法——用Python实现

图论中最短路径三剑客 前言一、Dijkstra算法&#xff08;贪心&#xff09;1.1 Dijkstra在生活中的应用举例1.2 设计思路1.3 算法应用实例1.3.1 以交通规划为例1.3.2 Dijkstra算法执行步骤1.3.3 python代码 1.4 时空复杂度 二、Floyd-Warshall算法&#xff08;动态规划&#xff…

2020年6月9日 Go生态洞察:VS Code Go扩展加入Go项目

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…