移动、缩放和旋转ImageView在触摸时无法工作

4
我已经尝试了几天让它工作,查看了其他答案,但似乎都对我无效:S
我向RelativeLayout添加了一个贴纸,希望在选中后使用OnTouch方法移动、缩放和旋转该贴纸(它具有调用setOnTouchListener的OnClickListener),请注意我可以添加N个贴纸。
private void addSticker(ImageView sticker)
{

    flMemeFrame.addView(sticker);

    sticker.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            {
                if (selectedView != null)
                {
                    CancelSelection(selectedView);
                }
                selectedView = v;

                v.setOnTouchListener(new View.OnTouchListener()
                {
                    private float mScaleFactor = 0.5f;
                    private float mRotationDegree = 0.f;
                    private float mFocusX = 0.f;
                    private float mFocusY = 0.f;
                    private int mScreenHeight;
                    private int mScreenWidth;
                    private Matrix matrix = new Matrix();//Các lớp Matrix giữ một ma trận 3x3 để di chuyển tọa độ.
                    private int mImageWidth, mImageHeight;
                    private ScaleGestureDetector mScaleDetector;
                    private RotateGestureDetector mRotateDetector;
                    private MoveGestureDetector mMoveDetector;

                    class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
                        @Override
                        public boolean onScale(ScaleGestureDetector detector) {
                            mScaleFactor *= detector.getScaleFactor();
                            mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 1.0f));
                            return true;
                        }
                    }

                    class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
                        @Override
                        public boolean onRotate(RotateGestureDetector detector) {
                            mRotationDegree -= detector.getRotationDegreesDelta();
                            return true;
                        }
                    }

                    class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
                        @Override
                        public boolean onMove(MoveGestureDetector detector) {
                            PointF d = detector.getFocusDelta();
                            mFocusX += d.x;
                            mFocusY += d.y;

                            return true;
                        }
                    }
                    @Override
                    public boolean onTouch(View v, MotionEvent event)
                    {
                        mImageHeight = v.getHeight();
                        mImageWidth = v.getWidth();

                        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
                        mRotateDetector = new RotateGestureDetector(context, new RotateListener());
                        mMoveDetector = new MoveGestureDetector(context, new MoveListener());

                        mScaleDetector.onTouchEvent(event);
                        mRotateDetector.onTouchEvent(event);
                        mMoveDetector.onTouchEvent(event);
                        float scaleImageCenterX = (mImageWidth * mScaleFactor) / 2;
                        float scaleImageCenterY = (mImageHeight * mScaleFactor) / 2;

                        matrix.reset();
                        matrix.postScale(mScaleFactor, mScaleFactor);
                        matrix.postRotate(mRotationDegree, scaleImageCenterX, scaleImageCenterY);
                        matrix.postTranslate(mFocusX - scaleImageCenterX, mFocusY - scaleImageCenterY);

                        ImageView view = (ImageView) v;
                        view.setScaleType(ImageView.ScaleType.MATRIX);
                        view.setImageMatrix(matrix);

                        return true;
                    }
                });
            }
        }
    });
}

这里是我设置图片的地方

ImageView sticker = new ImageView(context);
                RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT);
                rlp.addRule(RelativeLayout.CENTER_IN_PARENT);
                sticker.setLayoutParams(rlp);
addSticker(sticker);

这个应用程序已经编译完成并且没有崩溃,但是贴纸在触摸时没有任何反应 :(
我尝试过的链接:

http://code.almeros.com/android-multitouch-gesture-detectors#.V1Y0sZMrLMW

在安卓中使用多点触控进行旋转、缩放和移动

还有其他一些链接,我现在找不到了

有人能帮忙吗?

编辑:CancelSelection的代码(完全无关,因为我唯一要做的就是将selectedView设置为null并删除背景,我还删除了OnTouchListener,因为如果未选中视图,我不想移动/缩放/旋转视图)

@SuppressWarnings("deprecation")
public void CancelSelection(View v)
{
    if(isCaptionEditPanelOpen)
    {
        rlQuickEdit.setVisibility(View.GONE);
        rlQuickEdit = null;
        isCaptionEditPanelOpen = false;
    }
    //toogleButtonVisibility(false);
    v.setBackgroundColor(getResources().getColor(android.R.color.transparent));
    selectedView = null;
    v.setOnTouchListener(null);
}

我写了这个类,想看看是否可以在不涉及应用程序复杂性的情况下使其正常工作,结果相同:

package com.andujardev.imagerotation;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity
{
    Context context;
    ImageView imgRotate;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;

        imgRotate = (ImageView) findViewById(R.id.imgRotate);

        imgRotate.setOnTouchListener(new View.OnTouchListener()
        {
            private float mScaleFactor = 0.5f;
            private float mRotationDegree = 0.f;
            private float mFocusX = 0.f;
            private float mFocusY = 0.f;
            private int mScreenHeight;
            private int mScreenWidth;
            private Matrix matrix = new Matrix();
            private int mImageWidth, mImageHeight;
            private ScaleGestureDetector mScaleDetector;
            private RotateGestureDetector mRotateDetector;
            private MoveGestureDetector mMoveDetector;

            class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
                @Override
                public boolean onScale(ScaleGestureDetector detector) {
                    mScaleFactor *= detector.getScaleFactor();
                    mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 1.0f));
                    return true;
                }
            }

            class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
                @Override
                public boolean onRotate(RotateGestureDetector detector) {
                    mRotationDegree -= detector.getRotationDegreesDelta();
                    return true;
                }
            }

            class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
                @Override
                public boolean onMove(MoveGestureDetector detector) {
                    PointF d = detector.getFocusDelta();
                    mFocusX += d.x;
                    mFocusY += d.y;

                    return true;
                }
            }
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                mImageHeight = v.getHeight();
                mImageWidth = v.getWidth();

                mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
                mRotateDetector = new RotateGestureDetector(context, new RotateListener());
                mMoveDetector = new MoveGestureDetector(context, new MoveListener());

                mScaleDetector.onTouchEvent(event);
                mRotateDetector.onTouchEvent(event);
                mMoveDetector.onTouchEvent(event);
                float scaleImageCenterX = (mImageWidth * mScaleFactor) / 2;
                float scaleImageCenterY = (mImageHeight * mScaleFactor) / 2;

                matrix.reset();
                matrix.postScale(mScaleFactor, mScaleFactor);
                matrix.postRotate(mRotationDegree, scaleImageCenterX, scaleImageCenterY);
                matrix.postTranslate(mFocusX - scaleImageCenterX, mFocusY - scaleImageCenterY);

                ImageView view = (ImageView) v;
                view.setImageMatrix(matrix);

                return true;
            }
        });
    }
}

首先,您不理解手势的工作原理。上面的代码使用触摸,与单击不同。请在Google文档中了解更多关于所有手势的信息。 - GensaGames
这并没有错,我只是在用户使用 ClickListener 选择特定项目时启用手势,在 TouchListener 激活时,Click Listener 不会被调用,当用户在项目外单击时,图像将取消选择,并且您无法在其上使用手势。 - Daniel Andujar
这里另一个重要的事情是,我创建了另一个项目,使用手势代码(没有我的应用程序的所有复杂性),它也不起作用... - Daniel Andujar
2个回答

2
有趣的是,对于每一个触摸事件,您都会实例化一个新的ScaleGestureDetectorRotateGestureDetectorMoveGestureDetector。考虑到每个相应的手势检测器需要前一个触摸事件来确定和解释如何反应,因此这显然是您问题的重要部分,因为您为每个触摸事件创建了一个新的手势检测器。实际上,如果您查看Almeros检测器的源代码,onTouchEvent(MotionEvent ev)方法中指出:
Applications should pass a complete and consistent event stream to this method.
* A complete and consistent event stream involves all MotionEvents from the initial
* ACTION_DOWN to the final ACTION_UP or ACTION_CANCEL.

首先,您应该确保只创建一个探测器对象,这样它才能消耗所有的触摸事件。


我已经找到解决方案了,这是其中的一个问题,但我缺乏一个好的解释,谢谢!!另一个问题是,图像被设置为WRAP_CONTENT,而此代码不会移动/缩放/旋转ImageView,而是在imageView中Drawable,因此ImageView必须是MATCH_PARENT,这导致我遇到了更大的问题。我只能编辑最后添加的图像...(它将ImageView作为Matrix,所以在该矩阵中进行缩放和旋转,我希望矩阵是我的FrameLayout,但我不知道如何更改这个) - Daniel Andujar
好的,赏金期已经结束,到目前为止你是唯一一个达成其中一个要点的人,所以我会把赏金授予给你,但是我的问题并没有完全解决。 - Daniel Andujar

1
尝试这个...上面的代码不能工作的原因是因为TouchListener和ClickListener在上述情况下无法共同工作..Click需要您触摸并离开视图以发生事件。然而,Touch事件要求您仍在触摸视图...
private void addSticker(ImageView sticker)
{

flMemeFrame.addView(sticker);

sticker.setOnTouchListener(new View.OnTouchListener()
            {
                private float mScaleFactor = 0.5f;
                private float mRotationDegree = 0.f;
                private float mFocusX = 0.f;
                private float mFocusY = 0.f;
                private int mScreenHeight;
                private int mScreenWidth;
                private Matrix matrix = new Matrix();//Các lớp Matrix giữ một ma trận 3x3 để di chuyển tọa độ.
                private int mImageWidth, mImageHeight;
                private ScaleGestureDetector mScaleDetector;
                private RotateGestureDetector mRotateDetector;
                private MoveGestureDetector mMoveDetector;

                class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
                    @Override
                    public boolean onScale(ScaleGestureDetector detector) {
                        mScaleFactor *= detector.getScaleFactor();
                        mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 1.0f));
                        return true;
                    }
                }

                class RotateListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
                    @Override
                    public boolean onRotate(RotateGestureDetector detector) {
                        mRotationDegree -= detector.getRotationDegreesDelta();
                        return true;
                    }
                }

                class MoveListener extends MoveGestureDetector.SimpleOnMoveGestureListener {
                    @Override
                    public boolean onMove(MoveGestureDetector detector) {
                        PointF d = detector.getFocusDelta();
                        mFocusX += d.x;
                        mFocusY += d.y;

                        return true;
                    }
                }
                @Override
                public boolean onTouch(View v, MotionEvent event)
                {
                    mImageHeight = v.getHeight();
                    mImageWidth = v.getWidth();

                    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
                    mRotateDetector = new RotateGestureDetector(context, new RotateListener());
                    mMoveDetector = new MoveGestureDetector(context, new MoveListener());

                    mScaleDetector.onTouchEvent(event);
                    mRotateDetector.onTouchEvent(event);
                    mMoveDetector.onTouchEvent(event);
                    float scaleImageCenterX = (mImageWidth * mScaleFactor) / 2;
                    float scaleImageCenterY = (mImageHeight * mScaleFactor) / 2;

                    matrix.reset();
                    matrix.postScale(mScaleFactor, mScaleFactor);
                    matrix.postRotate(mRotationDegree, scaleImageCenterX, scaleImageCenterY);
                    matrix.postTranslate(mFocusX - scaleImageCenterX, mFocusY - scaleImageCenterY);

                    ImageView view = (ImageView) v;
                    view.setScaleType(ImageView.ScaleType.MATRIX);
                    view.setImageMatrix(matrix);

                    return true;
                }
            });
        }
    }

你可以监听DOWN和UP触摸事件来处理你想要的拖动效果。 - Dominic D'Souza
我这样做的原因是,当我点击图像时,我实际上激活了触摸功能,就好像我先选择图像,然后开始操作它,当我离开选择时,再返回正常的点击功能。 - Daniel Andujar
这个有什么新消息吗?:S - Daniel Andujar
我卡住了...我没有你使用的所有类和代码...缺少RotateGestureDetector和MoveGestureDetector...一开始我以为这是因为你同时使用了触摸和点击监听器的问题...但现在我感觉问题更深层次...你能分享所有的代码吗? - Dominic D'Souza
那个类在我发布的第一个链接上(code.almeros.com)。 - Daniel Andujar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接