Android 中 LinearLayout 的捏合缩放

2024-03-29

我需要缩放包含图像、文本视图等的整个布局。我发现缩放功能仅适用于图像视图。


创建自定义Layout调用的类ZoomeLinearLayout.

ZoomLinearLayout.java

public class ZoomLinearLayout extends LinearLayout implements ScaleGestureDetector.OnScaleGestureListener {

    private enum Mode {
        NONE,
        DRAG,
        ZOOM
    }

    private static final float MIN_ZOOM = 1.0f;
    private static final float MAX_ZOOM = 4.0f;

    private Mode mode = Mode.NONE;
    private float scale = 1.0f;
    private float lastScaleFactor = 0f;

    private float startX = 0f;
    private float startY = 0f;

    private float dx = 0f;
    private float dy = 0f;
    private float prevDx = 0f;
    private float prevDy = 0f;

    public ZoomLinearLayout(Context context) {
        super(context);
        init(context);
    }

    public ZoomLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ZoomLinearLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public void init(Context context) {
        final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this);
        this.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
                    case MotionEvent.ACTION_DOWN:
                        if (scale > MIN_ZOOM) {
                            mode = Mode.DRAG;
                            startX = motionEvent.getX() - prevDx;
                            startY = motionEvent.getY() - prevDy;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (mode == Mode.DRAG) {
                            dx = motionEvent.getX() - startX;
                            dy = motionEvent.getY() - startY;
                        }
                        break;
                    case MotionEvent.ACTION_POINTER_DOWN:
                        mode = Mode.ZOOM;
                        break;
                    case MotionEvent.ACTION_POINTER_UP:
                        mode = Mode.DRAG;
                        break;
                    case MotionEvent.ACTION_UP:
                        mode = Mode.NONE;
                        prevDx = dx;
                        prevDy = dy;
                        break;
                }
                scaleDetector.onTouchEvent(motionEvent);

                if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                    float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
                    float maxDy = (child().getHeight() - (child().getHeight() / scale)) / 2 * scale;
                    dx = Math.min(Math.max(dx, -maxDx), maxDx);
                    dy = Math.min(Math.max(dy, -maxDy), maxDy);
                    applyScaleAndTranslation();
                }

                return true;
            }
        });
    }

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

    @Override
    public boolean onScale(ScaleGestureDetector scaleDetector) {
        float scaleFactor = scaleDetector.getScaleFactor();
        if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {
            scale *= scaleFactor;
            scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
            lastScaleFactor = scaleFactor;
        } else {
            lastScaleFactor = 0;
        }
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector scaleDetector) {
    }

    private void applyScaleAndTranslation() {
        child().setScaleX(scale);
        child().setScaleY(scale);
        child().setTranslationX(dx);
        child().setTranslationY(dy);
    }

    private View child() {
        return getChildAt(0);
    }

}

Then in Layout文件,包裹你的LinearLayout你想用哪个来缩放ZoomLinearLayout. 请注意,您只有一个直系子女ZoomLinearLayout.

 <com.asif.test.ZoomLinearLayout
    android:layout_width="match_parent"
    android:id="@+id/zoom_linear_layout"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </LinearLayout>

</com.asif.test.ZoomLinearLayout>

Now in Activity, 创造ZoomLinearLayout对象并设置onTouch()为它举办的活动。

final ZoomLinearLayout zoomLinearLayout = (ZoomLinearLayout) findViewById(R.id.zoom_linear_layout);
zoomLinearLayout.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        zoomLinearLayout.init(MainActivity.this);
        return false;
    }
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 中 LinearLayout 的捏合缩放 的相关文章

随机推荐

  • 多行 UIButton 和自动布局

    我创建了一个视图控制器 如下所示 我希望两个顶部按钮与整个视图的左 右边缘之间始终保持 20 个点 它们也应该始终具有相同的宽度 我已经为所有这一切创建了约束 并且它完全按照我想要的方式工作 问题是垂直限制 按钮应始终位于顶部边缘下方 20
  • 如何在 Dancer 模板中制作特定于页面的标题?

    我有一个标准的 Perl Dancer 应用程序 使用 Template Toolkit 作为渲染引擎 有两条路线 get gt sub template index get foo gt sub template foo My views
  • Doctrine2 将实体导出到数组

    I have Product具有多对一的实体Category实体 我需要商店Product会议中 首先我尝试实施 Serializable产品上的界面 我应该如何序列化我的相关Category实体 我是否也应该实施 Serializable
  • 错误!代码 EPERM

    我正在使用 Node v6 11 2 npm v5 3 0 和 Angular cli v1 2 7 我的大部分 npm 安装突然收到以下错误消息 以前没见过 mmeppiel MC LT MMEPPIEL MINGW64 Desktop
  • 我可以在调用 Flask app.run 之后让 Python 代码继续执行吗?

    尽管过去 30 年来我一直在使用其他语言进行编程 但我才刚刚开始使用 Python 我想让我的第一个应用程序保持简单 所以我从一个托管在 Raspberry Pi 上的小型家庭自动化项目开始 我的代码工作正常 控制阀门 读取流量传感器并在显
  • 使用 Django 和 Twilio 通过短信进行一次性用户身份验证

    我正在 Django 中为我正在创建的移动应用程序编写后端 我需要在用户第一次通过短信打开移动应用程序时对其进行身份验证 以验证其是否为真人 需要发生的事情如下 用户在应用程序中输入电话号码 服务器然后向用户发送带有验证码的短信 然后用户在
  • 如何通过 VSCode 始终在新窗口中打开文件?

    Using MacOS Mojave VSCode 1 28 2 我在文本编辑中使用 VSCode 如 js txt csv 当我双击并在 Finder 或桌面中打开文件 或 在 VSCode 中打开 时 如果我打开另一个工作区 它会在与我
  • 我可以为 C# 中的匿名类指定一个有意义的名称吗?

    我们都知道 当我们创建这样的匿名类时 var Employee new ID 5 Name Prashant 在运行时它将是以下类型 lt gt f AnonymousType0
  • gcc 优化标志 -O3 使代码比 -O2 慢

    我找到这个话题为什么处理排序数组比处理未排序数组更快 https stackoverflow com questions 11227809 why is processing a sorted array faster than an un
  • 如何发送 AJAX POST 请求并播放响应中的音频?

    我正在构建一个应用程序 用户可以单击按钮 然后它将数据发送到服务器 然后 服务器根据请求 很可能是 POST 中的数据计算音频 并将 WAV 文件返回到浏览器 我已经构建了接受 post 请求并使用 wav 文件响应的部分 但我不知道如何在
  • 将 QR 码调配到设备所有者模式失败

    我有一台运行 Android 7 1 1 的设备 我正在构建示例 DPC 应用程序以准备制作 COSU kiosk 应用程序 但我在配置设置中不断遇到错误 我采取的步骤 将设备恢复出厂设置 成功扫描二维码配置屏幕上的代码 应用程序下载成功并
  • Angular Http - toPromise 或订阅

    我观看了一些有关 Angular 的课程 发现有不同的方法来管理来自 Http 请求的数据 使用可观察量 map subscribe 使用承诺 toPromise then catch 我用过toPromise 在我的应用程序中 我发现它类
  • 如何添加不同的背景颜色到交替行到列表框项目 Windows Phone 8

    我是 Windows Phone 开发新手 我在列表框中显示数据 对于列表框中的所有行 背景颜色都是相同的 但我想为列表框项目的交替行添加两种不同的颜色 下面是列表视图的代码
  • 如何将图片添加到 javaFX 2.0 netbeans 项目

    您好 感谢您抽出宝贵的时间 我是 Netbeans 新手 我正在使用 Netbeans 7 1 RC1 版本 我遇到的问题是我似乎无法将图像添加到项目中 我正在 JavaFX 2 0 中设计一个 Web 应用程序 需要一张 jpg 图片作为
  • 对包含字符串和数字的数据帧索引进行排序

    我有一个数据框 其中索引值是由下划线分隔的字符串和数字的混合 sub int1 ICA int2 我想首先使用 int1 对列索引进行排序 然后使用 int2 对列索引进行排序 预期输出为 sub 1 ICA 1 sub 1 ICA 2 s
  • Spring 4 中有多个@ComponentScan?

    我正在使用 Spring 4 16 和 Java Annotations 我想做一些类似的事情 Configuration ComponentScan basePackages com example business includeFil
  • 自 iOS 5.1 以来,自定义 MPVolumeView 拇指图像未垂直居中

    我正在构建一个需要 MPVolumeView 来控制音量的应用程序 它在 iOS 5 1 之前工作得很好 但自 5 1 更新以来 拇指图像不再垂直居中 我尝试了一些方法 例如更改想象尺寸 调整视图 和滑块 的大小 但似乎没有任何效果 拇指不
  • Flutter 未检测到 Android SDK

    我一直在尝试让 flutter 来检测 Android SDK flutter doctor returns PS I Projects Flutter fluttertest flutterproject gt flutter docto
  • 使用类型化视图时如何在 ActionFilterAttribute 中设置模型数据

    我使用强类型视图 其中所有 ViewModel 都继承类 BaseViewModel 在装饰所有控制器的 ActionFilter 中 我想使用模型 现在我只能这样访问它 public override void OnActionExecu
  • Android 中 LinearLayout 的捏合缩放

    我需要缩放包含图像 文本视图等的整个布局 我发现缩放功能仅适用于图像视图 创建自定义Layout调用的类ZoomeLinearLayout ZoomLinearLayout java public class ZoomLinearLayou