Android 中基于一个手柄旋转和缩放视图

2023-12-02

我正在尝试根据 Android 中的一个“拖动”手柄来旋转和缩放视图。随着布局旋转和视图大小调整,最终结果应该是拖动手柄跟随用户手指移动。

这是基于结合这两个问题:

  1. 如何使用手柄在android中缩放视图?
  2. 在android中绕两点旋转不起作用

唯一看起来错误的是轮换代码。

这是我的活动代码:

public class MainActivity extends Activity {
    ImageView imageView;
    ImageView dragHandle;
    RelativeLayout layout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.imageView1);
        imageView.setBackgroundColor(Color.MAGENTA);
        dragHandle = (ImageView) findViewById(R.id.imageView2);
        dragHandle.setBackgroundColor(Color.CYAN);
        layout = (RelativeLayout) findViewById(R.id.relativeLayout2);
        layout.setBackgroundColor(Color.YELLOW);
        setUpResize();

    }

    public void setUpResize() {
        dragHandle.setOnTouchListener(new View.OnTouchListener() {

            float centerX, centerY, startR, startScale, startX, startY;

            float startAngle;
            float zeroAngle;
            int firstPointX;
            int firstPointY;

            public boolean onTouch(View v, MotionEvent e) {

                if (e.getAction() == MotionEvent.ACTION_DOWN) {

                    // calculate center of image
                    centerX = (imageView.getLeft() + imageView.getRight()) / 2f;
                    centerY = (imageView.getTop() + imageView.getBottom()) / 2f;

                    // recalculate coordinates of starting point
                    startX = e.getRawX() - dragHandle.getX() + centerX;
                    startY = e.getRawY() - dragHandle.getY() + centerY;

                    // get starting distance and scale
                    startR = (float) Math.hypot(e.getRawX() - startX, e.getRawY() - startY);
                    startScale = imageView.getScaleX();

                    /*
                     * Rotate code
                     */

                    int[] locationOfLayout = new int[2];
                    int[] locationOfDrag = new int[2];

                    layout.getLocationOnScreen(locationOfLayout);
                    dragHandle.getLocationOnScreen(locationOfDrag);

                    firstPointX = locationOfLayout[0];
                    firstPointY = locationOfLayout[1];

                    float secondPointX = e.getRawX();
                    float secondPointY = e.getRawY();

                    zeroAngle = findRotation(firstPointX, firstPointY, secondPointX, secondPointY); // remember
                                                                                                    // "zero"
                                                                                                    // angle
                    startAngle = layout.getRotation(); // remember angle at
                                                        // which layout is
                                                        // rotated at the start

                } else if (e.getAction() == MotionEvent.ACTION_MOVE) {

                    // calculate new distance
                    float newR = (float) Math.hypot(e.getRawX() - startX, e.getRawY() - startY);

                    // set new scale
                    float newScale = newR / startR * startScale;
                    imageView.setScaleX(newScale);
                    imageView.setScaleY(newScale);

                    // move handler image
                    dragHandle.setX(centerX + imageView.getWidth() / 2f * newScale);
                    dragHandle.setY(centerY + imageView.getHeight() / 2f * newScale);

                    /*
                     * Rotate code
                     */

                    layout.setRotation(findRotation(firstPointX, firstPointY, e.getRawX(), e.getRawY()) - zeroAngle
                            + startAngle); // rotate relative to start and zero
                                            // angle

                } else if (e.getAction() == MotionEvent.ACTION_UP) {

                }
                return true;
            }
        });
    }

    private float findRotation(float firstPointX, float firstPointY, float secondPointX, float secondPointY) {
        double delta_x = (secondPointX - firstPointX);
        double delta_y = (secondPointY - firstPointY);
        double radians = Math.atan2(delta_y, delta_x);
        return (float) Math.toDegrees(radians);
    }
}

xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/relativeLayout2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" >

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_centerVertical="true"
            android:src="@drawable/ic_launcher" />

        <ImageView
            android:id="@+id/imageView2"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_below="@+id/imageView1"
            android:layout_toRightOf="@+id/imageView1"
            android:src="@drawable/meanicons" />

    </RelativeLayout>

</RelativeLayout>

如果您需要使用一个处理程序图标同时调整图像大小和旋转图像,则应执行一些三角计算。

根据图像的初始角度和连接图像中心与当前手指位置的矢量旋转的角度,计算图像应旋转的角度并不困难。稍微复杂一点的任务是将处理程序放置在屏幕的适当位置,使其始终连接主图像的一角。

public void setUpResize() {
    dragHandle.setOnTouchListener(new View.OnTouchListener() {

        float centerX, centerY, startR, startScale, startX, startY, startRotation, startA ;

        public boolean onTouch(View v, MotionEvent e) {

            if (e.getAction() == MotionEvent.ACTION_DOWN) {

                centerX = (imageView.getLeft() + imageView.getRight()) / 2f;
                centerY = (imageView.getTop() + imageView.getBottom()) / 2f;

                startX = e.getRawX() - dragHandle.getX() + centerX;
                startY = e.getRawY() - dragHandle.getY() + centerY; 

                startR = (float) Math.hypot(e.getRawX() - startX, e.getRawY() - startY);
                startA = (float) Math.toDegrees(Math.atan2(e.getRawY() - startY, e.getRawX() - startX));

                startScale = imageView.getScaleX();
                startRotation = imageView.getRotation();

            } else if (e.getAction() == MotionEvent.ACTION_MOVE) {

                float newR = (float) Math.hypot(e.getRawX() - startX, e.getRawY() - startY);
                float newA = (float) Math.toDegrees(Math.atan2(e.getRawY() - startY, e.getRawX() - startX));
                float newScale = newR / startR * startScale;
                float newRotation = newA - startA + startRotation;

                imageView.setScaleX(newScale);
                imageView.setScaleY(newScale);
                imageView.setRotation(newRotation);


                // ----- this part takes some effort to understand... ------
                dragHandle.setX((float) (centerX + Math.hypot(imageView.getWidth(), imageView.getHeight())/2f * newScale 
                        * Math.cos(Math.toRadians(newRotation) + Math.atan2(imageView.getHeight(), imageView.getWidth()))));

                dragHandle.setY((float) (centerY + Math.hypot(imageView.getWidth(), imageView.getHeight())/2f * newScale 
                        * Math.sin(Math.toRadians(newRotation) + Math.atan2(imageView.getHeight(), imageView.getWidth()))));
                //-----------------------------------------------------------

                dragHandle.setPivotX(0);
                dragHandle.setPivotY(0);
                dragHandle.setRotation(newRotation);


            } else if (e.getAction() == MotionEvent.ACTION_UP) {

            }
            return true;
        }
    });
}

那么,我在做什么?

Math.hypot(imageView.getWidth(), imageView.getHeight()) / 2f * newScale

--这计算主图像对角线的一半长度,i。 e.其中心与角点之间的距离

Math.atan2(imageView.getHeight(), imageView.getWidth())

--这是对角线最初旋转的角度(因为图像不能是正方形,所以这个角度并不总是 45 度)

Math.cos(Math.toRadians(newRotation) + Math.atan2(imageView.getHeight(), imageView.getWidth()))

--这为我们提供了单位向量 X 轴上的投影,旋转了一个由图像旋转角度及其对角线初始旋转角度组成的角度。乘以对角线长度的一半后,我们得到图像角点的X。

与 Y 相同,但使用sin代替cos.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 中基于一个手柄旋转和缩放视图 的相关文章

随机推荐

  • 如何将 UTF-8 std::string 转换为 UTF-16 std::wstring?

    如果我有 UTF 8std string如何将其转换为 UTF 16std wstring 实际上 我想比较两个波斯语单词 这就是你如何做到的C 11 std string str your string in utf8 std wstri
  • Firebase 服务器发送事件 - 如何构建 Java / JavaScript 客户端

    我是 Firebase 的新手 正在构建一个原型来测试是否适合我们的需求 我已经启动并运行了一个聊天示例 到目前为止一切顺利 接下来是需要倾听变化 我尝试使用 Java 和 JavaScript 连接到支持服务器发送事件的 REST API
  • 如何指定R-shiny和shinyFiles保存文件的文件和路径?

    我正在使用 R shiny 并希望将数据框保存为 Excel 文件 为此 我使用 shinyFiles 包 以便用户可以指定 excel 文件的存储位置 服务器R 图书馆 闪亮 库 闪亮的文件 shinyServer function in
  • 多个准备好的语句的问题

    问题就在这里 我有一份准备好的声明 如下所示 select something db gt stmt init select something gt prepare SELECT whatever FROM table select so
  • 如何初始化和使用静态结构[重复]

    这个问题在这里已经有答案了 我在类中定义了一个静态结构 但它导致错误为 Error 错误 LNK1120 1 个未解析的外部 我的头文件 class CornerCapturer static struct configValues int
  • Sagepay 5006 错误代码修复

    谁能告诉我为什么 sagepay 会抛出 5006 无法重定向到供应商的网站 我可以将交易发布到 sagepay 并且可以在 sagepay 端提供信用卡信息 但是 我的问题是 一旦它返回到我的通知页面 它就会抛出错误 5006 我最终无法
  • 在jquery中的anchor中添加span标签

    如何在锚点内添加span标签 将其更改为 a href somewhere html Here is the link to somewhere a 用 jquery 对此 a href somewhere html span Here i
  • 如何使用正则表达式删除字符串中的重复字符?

    我需要替换字符串中的重复字符 我尝试使用 outputString str replaceAll 1 这会替换重复的字符 但字符的位置会发生变化 如下所示 input haih output aih 但我需要得到一个输出hai 也就是说 字
  • 使用 indy / delphi 组件通过 https 发布文件

    我正在尝试使用 delphi 中的 Indy 组件通过 https 上传文件 这是我的代码 HTTP TIdHTTP Create Self IOHandler TIdSSLIOHandlerSocketOpenSSL Create HTT
  • 如何计算出响应式 CSS 的正确最小宽度和最大宽度值?

    我现在刚刚开始研究响应式 CSS 和设计 我想知道如何计算出各种设备宽度 我不想花一整天的时间测试每一个可能的移动设备 我只想让响应式布局足以发挥其作用 我看到一些网站使用 media only screen and max device
  • 在 python 脚本和 applescript 之间传递和接收值

    我对 python 和 applescript 很陌生 我有一个 python 脚本正在调用 2 个 applescripts 我想在 python 中定义一些全局变量并传递给 applescript 1 这些值将由 applescript
  • Azure 逻辑应用 SQL ODATA 按日期筛选

    我正在创建一个新的逻辑应用程序 它读取一个表 其中DateCreated lt ADDDAYS 60 GETDATE 并更新Archived bit to 1 但是 我一生都无法弄清楚如何将该过滤器实现为 ODATA 查询的一部分 到目前为
  • (Robotium) 操作栏向上/主页按钮单击

    I use Robotium作为我的 Android 应用程序的 Junit 测试库 我写了一些效果很好的测试 但是当我尝试编写测试时原生操作栏 s 单击向上 主页按钮 失败了 我的测试代码非常简单 Solo solo new Solo g
  • 为什么我会收到准备好的语句的语法错误? [复制]

    这个问题在这里已经有答案了 我已经编写了一个准备好的语句 但它在 给出了语法错误 我无法理解出了什么问题 它应该传递电影名称并作为该电影的导演获得结果 stmt getConnection createStatement String sq
  • 将 numpy 数组写入 lmdb

    我正在尝试将 python 中的一些 numpy 数组写入 lmdb import numpy as np import lmdb def write lmdb filename lmdb env lmdb open filename ma
  • Android Eclipse 错误:“Gson 无法解析为类型”

    我对 Java Eclipse 和 Android 比较陌生 所以这可能是一个完全愚蠢的问题 但我还是要问它 我正在学习一个项目来测试连接到 flickr api 并简单地显示最近的图像 我现在想要解析从 flickr 收到的 JSON 我
  • 如何防止 scanf 失败导致无限循环

    该代码应该可以换一美元并且运行良好 但教授说他将随字母一起输入随机数字 它可以很好地处理数字 但是当输入字母时会出现无限循环 有什么建议吗 include
  • 如何在android中对本地数据库进行语音识别检查?

    您是否还记得在旧手机中您可以创建语音快捷方式来呼叫某人 我正在尝试在 android 中制作一个具有该功能的应用程序 用户录制想要控制应用程序的单词或声音 语音识别器只会检查它听到的声音是否等于之前录制的声音 有谁知道如何制作这个或知道指南
  • 在Python中调整OSX系统音频音量

    我想通过 python 脚本调整 OSX 中的系统音量 这个问题关于实现键盘快捷键告诉我如何在 applescript 中执行此操作 但我真的很想从 python 脚本中执行此操作 而不使用 os system popen 等 理想情况下
  • Android 中基于一个手柄旋转和缩放视图

    我正在尝试根据 Android 中的一个 拖动 手柄来旋转和缩放视图 随着布局旋转和视图大小调整 最终结果应该是拖动手柄跟随用户手指移动 这是基于结合这两个问题 如何使用手柄在android中缩放视图 在android中绕两点旋转不起作用