当前位置: 首页 > article >正文

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

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


http://www.kler.cn/news/149382.html

相关文章:

  • Oracle整体架构
  • IP-Adapter:文本兼容图像提示适配器,用于文本到图像扩散模型
  • 振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(9)
  • 【代码】数据驱动的多离散场景电热综合能源系统分布鲁棒优化算法matlab/yalmip+cplex/gurobi
  • java学习part21枚举
  • 选择跨网数据摆渡系统时,你最关注的功能是哪些?
  • 设置MATLAB启动时弹到上次退出时的工作文件夹
  • java List集合(ArrayList,LinkedList,Vector)
  • 【黑马程序员】——微服务全套——实战篇1
  • 5 时间序列预测入门:LSTM+Transformer
  • 数组中的第 K 个最大元素(C++实现)
  • UE5学习(游戏存档,两种适应性的射线检测,时间膨胀)
  • 解决Python中删除临时文件时的文件占用问题
  • C++调用GPIB驱动头文件ni488.h内容详细分拆解
  • SEO工具-免费功能最全的5款SEO工具
  • 如何选择一款安全稳定的跨境浏览器?
  • 西南科技大学(数据结构A)期末自测练习二
  • TCP与UDP
  • pgsql 更新A表的x字段通过查询b表的z字段
  • scoi - 2013 -- 数数题解(这道题是一个非常好的数位dp题)
  • 利用sql语句来统计用户登录数据的实践
  • Pytorch:torch.utils.data.DataLoader()
  • 系列五、Spring整合MyBatis不忽略mapper接口同目录的xxxMapper.xml
  • 搜索引擎语法
  • Alibaba Java诊断工具Arthas查看Dubbo动态代理类
  • 【古月居《ros入门21讲》学习笔记】14_参数的使用与编程方法
  • 你知道显卡型号上的数字是什么意思吗?数字越大就越好吗?
  • 34.基于webpack搭建开发环境
  • ground truth 在深度学习任务中代表的是什么意思?
  • 第二证券:机构密集调研消费电子、半导体产业链