如何使用句柄在android中缩放视图?

Posted

技术标签:

【中文标题】如何使用句柄在android中缩放视图?【英文标题】:How to scale a view in android using a handle? 【发布时间】:2014-05-30 07:21:56 【问题描述】:

我正在尝试实现一个句柄来缩放 android 中的视图。我希望能够只用一根手指调整图像大小,而不是使用多点触控之类的东西。

这是我的活动代码。我觉得好像我很接近有五件事不能正常工作。

    缩放已关闭。它的增长速度比它应该的要快得多。 已解决谢谢@Salauyou 视图只会扩大,不会缩小。 已解决谢谢@Salauyou 句柄视图不随图像移动。 已解决谢谢@Salauyou 缩放开始时非常小已解决感谢@Salauyou 手柄没有完全跟随您的手指。

我正在寻找可以实现此类功能的任何帮助。无论是图书馆还是有人可以帮助我处理我已经拥有的代码。我找到了一个有助于图像多点触控缩放的库 (https://github.com/brk3/android-multitouch-controller),但我能找到的唯一指针是如何实现缩放的增加。这必须通过使用两个点并找到它们之间的距离来完成。

我的 java 活动:

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() 

            int[] touchPoint = new int[2];
            int[] centerOfImage = new int[2];

            double originalDistance = 0;
            double modifiedDistance = 0;

            float originalScale = 0;
            float modifiedScale = 0;

            public boolean onTouch(View v, MotionEvent motionEvent) 

                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) 

                    centerOfImage[0] = (int) (imageView.getX() + imageView.getWidth() / 2);
                    centerOfImage[1] = (int) (imageView.getY() + imageView.getHeight() / 2);

                    touchPoint[0] = (int) motionEvent.getRawX();
                    touchPoint[1] = (int) motionEvent.getRawY();

                    int[] p = new int[2];
                    p[0] = touchPoint[0] - centerOfImage[0];
                    p[1] = touchPoint[1] - centerOfImage[1];

                    originalDistance = (float) Math.sqrt(p[0] * p[0] + p[1] * p[1]);
                    originalScale = imageView.getScaleX();

                 else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) 
                    touchPoint[0] = (int) motionEvent.getRawX();
                    touchPoint[1] = (int) motionEvent.getRawY();

                    int[] p = new int[2];
                    p[0] = (touchPoint[0] + p[0] - centerOfImage[0]);
                    p[1] = (touchPoint[1] + p[1] - centerOfImage[1]);
                    modifiedDistance = Math.hypot(touchPoint[0] - centerOfImage[0], touchPoint[1] - centerOfImage[1]);

                    Log.e("resize", "original " + imageView.getWidth() + " modified: " + imageView.getHeight());
                    modifiedScale = (float) (modifiedDistance / originalDistance * originalScale);

                    imageView.setScaleX(modifiedScale);
                    imageView.setScaleY(modifiedScale);

                    dragHandle.setX(centerOfImage[0] + imageView.getWidth()/2 * modifiedScale);
                    dragHandle.setY(centerOfImage[1] + imageView.getHeight()/2 * modifiedScale);

                 else if (motionEvent.getAction() == MotionEvent.ACTION_UP) 

                
                return true;
            
        );
    

我的 xml:

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

    <RelativeLayout
        android:id="@+id/relativeLayout2"
        android:layout_
        android:layout_
        android:layout_centerInParent="true" >

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

        <ImageView
            android:id="@+id/imageView2"
            android:layout_
            android:layout_
            android:layout_below="@+id/imageView1"
            android:layout_toRightOf="@+id/imageView1"
            android:src="@drawable/dragArrow" />

    </RelativeLayout>

</RelativeLayout>

【问题讨论】:

有什么理由不使用developer.android.com/reference/android/widget/… ? 我不认为拥有附件缩放控件是我需要的。对不起。 句柄视图不随图像移动。 因为它不应该。您的大图像被视为容器的原始大小,因为setScaleX() 和其他转换方法仅影响视图的绘制,而不影响其布局空间。 Math.sqrt(p[0] * p[0] + p[1] * p[1]) 可以很容易地替换为Math.hypot(p[0], p[1]) - 它更具可读性、精确性和有效性。 所以 scale 不会改变大小? @Salauyou? 【参考方案1】:

所以...主要问题是MotionEventgetRawX()getRawY() 方法提供绝对屏幕坐标,而getX()getY() 提供布局坐标。因此,进度条和状态条的高度坐标不同,所以在获取触摸坐标时,我们应该相对于布局重新计算它们。

dragHandle.setOnTouchListener(new View.OnTouchListener() 

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

    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();

         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);

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

        
        return true;
    
);

另外,我用库方法替换了假设计算,并将所有坐标声明为浮点数以避免不必要的转换。

【讨论】:

这很好用。我现在需要旋转和缩放,但是在将两者结合起来时遇到了问题。 ***.com/questions/23115472/… 你想通过拖动一个处理程序同时执行2个操作吗? 是的。我曾经在 ios 上看到一个可以做到这一点的应用程序。而且效果很好,但我不记得名字了。我希望它像捏缩放一样工作。如果你捏缩放,你也可以同时旋转。所以是的,一次 2 次操作。 所以你想捏缩放/旋转(使用 2 个手指)或拖动缩放/旋转(使用 1 个手指和处理程序图标)?方法和解决方案会有所不同。

以上是关于如何使用句柄在android中缩放视图?的主要内容,如果未能解决你的问题,请参考以下文章

Android:自定义视图缩放/捏合

如何在android中实现图像视图的缩放效果?

Android:缩放两个视图

Android:谷歌照片,如具有缩放功能的网格视图

Android:如何将地图视图的缩放级别设置为当前位置周围 1 公里半径?

如何从 webview 隐藏文本选择句柄:android