8

我正在开发一个应用程序,该应用程序具有通过拖动其右下角按钮来调整和旋转图像视图的功能。

我看到一个应用程序的功能是,如果我们对角拖动右下角按钮 imageview 大小已调整大小,或者如果我们拖动按钮左侧或右侧方向 imageview 已按方向旋转。我希望在我的应用程序中实现此功能

我正在努力实现单指旋转以及调整图像视图的大小。

请以正确的方式指导我。在此处输入图像描述


我正在尝试此代码,并尝试应用缩放和旋转但无法做到,请帮助我。belove 代码来做缩放和旋转手指的动作。

public class ScaleActivity extends Activity {

ViewGroup lLayout;
static ImageView img, backgrndImg;
Canvas mCanvas;
float d;
private float mAspectQuotient;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    lLayout = (FrameLayout) findViewById(R.id.lLayout);

    final CropView cv = new CropView(this);
    lLayout.addView(cv);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

public class CropView extends ImageView {
    private static final int SELECTION_RECT_PAINT_COLOR = 0xFF000000;
    private static final int SELECTION_RECT_FILL_COLOR = 0x70FFFFFF;
    private static final int TOUCH_TOLERANCE = 25;
    private static final int xInc = 25;
    private static final int yInc = 25;
    Paint paint = new Paint();
    private int initial_size = 200;
    private Point leftTop, rightBottom, center, previous, currentPoint,
            rectPos;
    private Paint fillPaint;
    private Paint rectPaint;
    protected Rect selection, dest;
    private boolean isAffectedBottom = false;
    Bitmap bitmap, backgroundBitmap;
    Rect rectf;
    Rect knobRect;
    private Context mContext;
    int width, height;
    private Matrix matrix = new Matrix();
    Bitmap resizedBitmap;

    // Adding parent class constructors
    public CropView(Context context) {
        super(context);

        mContext = context;

        backgroundBitmap = BitmapFactory.decodeResource(getContext()
                .getResources(), R.drawable.toast_bkgrd);
        bitmap = BitmapFactory.decodeResource(getContext().getResources(),
                R.drawable.aviary_adjust_knob);

        rectPaint = new Paint();
        rectPaint.setStyle(Style.STROKE);
        rectPaint.setColor(SELECTION_RECT_PAINT_COLOR);
        fillPaint = new Paint();
        fillPaint.setStyle(Style.FILL);
        fillPaint.setColor(SELECTION_RECT_FILL_COLOR);
        currentPoint = new Point(getWidth() / 2, getHeight() / 2);
        width = backgroundBitmap.getWidth();
        height = backgroundBitmap.getHeight();
        initCropView();
    }

    public CropView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        initCropView();
    }

    public CropView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initCropView();
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCanvas = canvas;
        if (leftTop.equals(0, 0))
            resetPoints();
        mCanvas.save();
        resizedBitmap = Bitmap.createBitmap(backgroundBitmap, 0, 0,
                backgroundBitmap.getWidth(), backgroundBitmap.getHeight(),
                matrix, true);
        // mCanvas.drawBitmap(backgroundBitmap, matrix, rectPaint);
        mCanvas.drawBitmap(resizedBitmap, null, selection, rectPaint);
        mCanvas.drawBitmap(bitmap, selection.right - 25,
                selection.bottom - 25, null);
        rectPos.set(selection.left, selection.top);

        mCanvas.restore();

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int eventaction = event.getAction();
        switch (eventaction) {
        case MotionEvent.ACTION_DOWN:
            touchDown((int) event.getX(), (int) event.getY());
            previous.set((int) event.getX(), (int) event.getY());

            break;
        case MotionEvent.ACTION_MOVE:
            touchMove((int) event.getX(), (int) event.getY());

            if (isActionInsideRectangle(event.getX(), event.getY())
                    && !isAffectedBottom) {
                drag((int) event.getX(), (int) event.getY());
                invalidate(); // redraw rectangle
                previous.set((int) event.getX(), (int) event.getY());
            }
            previous.set((int) event.getX(), (int) event.getY());
            break;
        case MotionEvent.ACTION_UP:
            touchUp((int) event.getX(), (int) event.getY());
            previous = new Point();
            break;
        }
        return true;
    }

    private void initCropView() {
        paint.setColor(Color.WHITE);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(5);
        leftTop = new Point();
        rightBottom = new Point();
        center = new Point();
        previous = new Point();
        rectPos = new Point();

    }

    public void resetPoints() {
        center.set(getWidth() / 2, getHeight() / 2);
        leftTop.set((getWidth() - initial_size) / 2,
                (getHeight() - initial_size) / 2);
        rightBottom.set(leftTop.x + initial_size, leftTop.y + initial_size);
        selection = new Rect(leftTop.x, leftTop.y, rightBottom.x,
                rightBottom.y);
        knobRect = new Rect(selection.right, selection.bottom,
                bitmap.getWidth(), bitmap.getHeight());
        dest = selection;
    }

    private boolean isActionInsideRectangle(float x, float y) {
        int buffer = 10;
        return (x >= (selection.left) && x <= (selection.right)
                && y >= (selection.top) && y <= (selection.bottom)) ? true
                : false;
    }

    void touchDown(int x, int y) {

        System.out.println("selection " + selection);
        int dx = (previous.x - x) / 2;
        int dy = (previous.y - y) / 2;
        // d= rotation(dx,dy);
        currentPoint.set(x, y);
        if (pointsAreClose(x, y, selection.right, selection.bottom)) {
            isAffectedBottom = true;
            System.out.println("isAffectedBottom " + isAffectedBottom);
        }
    }

    void touchMove(int x, int y) {
        currentPoint.set(x, y);
        if (isAffectedBottom) {
            int dx = (previous.x - x) / 2;
            int dy = (previous.y - y) / 2;
            double startAngle = getAngle(previous.x, previous.y);

            double currentAngle = getAngle(x, y);

            matrix.postRotate((float) (startAngle - currentAngle),
                    selection.width() / 2.0f, selection.height() / 2.0f);
            // selection.inset(dx, dy);             
            invalidate();
        }
    }

    void touchUp(int x, int y) {
        currentPoint.set(x, y);
        isAffectedBottom = false;
    }

    private boolean pointsAreClose(float x1, float y1, float x2, float y2) {
        return Math.hypot(x1 - x2, y1 - y2) < TOUCH_TOLERANCE;
    }

    private void drag(int x, int y) {
        int movement;
        movement = x - previous.x;
        int movementY = y - previous.y;
        selection.set(selection.left + movement, selection.top + movementY,
                selection.right + movement, selection.bottom + movementY);
        selection.sort();
        invalidate();
    }


    /**
     * Calculate the degree to be rotated by.
     * 
     * @param event
     * @return Degrees
     */
    // private float rotation(float dx, float dy) {
    //
    // // double delta_x = (dx);
    // // double delta_y = (dy);
    // double radians = Math.atan2((selection.left) - (previous.y),
    // (selection.top) - (previous.x));
    // double radians2 = Math.atan2((selection.left) - (dy),
    // (selection.top) - (dx));
    //
    // System.out.println("radians" + radians);
    // System.out.println("" + radians2);
    // System.out.println("radians2-radians" + (radians2 - radians));
    // System.out.println(Math.toDegrees(radians2 - radians));
    // return (float) Math.toDegrees(radians2 - radians);
    //
    // }

    private double getAngle(double xTouch, double yTouch) {
        double x = xTouch - (getWidth() / 2d);
        double y = getHeight() - yTouch - (getHeight() / 2d);

        switch (getQuadrant(x, y)) {
        case 1:
            System.out.println("1");
            return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;

        case 2:
        case 3:
            System.out.println("32");
            return 180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);

        case 4:
            System.out.println("4");
            return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;

        default:
            // ignore, does not happen
            return 0;
        }
    }

    /**
     * @return The selected quadrant.
     */
    private int getQuadrant(double x, double y) {
        if (x >= 0) {
            return y >= 0 ? 1 : 4;
        } else {
            return y >= 0 ? 2 : 3;
        }
    }
}

}
4

3 回答 3

10

我设计了一个可以根据您的需要工作的布局。在此处下载演示

Java 文件

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class ClipArt extends RelativeLayout {
    int baseh;
    int basew;
    int basex;
    int basey;
    ImageButton btndel;
    ImageButton btnrot;
    ImageButton btnscl;
    RelativeLayout clip;
    Context cntx;
    boolean freeze = false;
    int h;
    int i;
    ImageView image;
    String imageUri;
    boolean isShadow;
    int iv;
    RelativeLayout layBg;
    RelativeLayout layGroup;
    RelativeLayout.LayoutParams layoutParams;
    public LayoutInflater mInflater;
    int margl;
    int margt;
    float opacity = 1.0F;
    Bitmap originalBitmap;
    int pivx;
    int pivy;
    int pos;
    Bitmap shadowBitmap;
    float startDegree;
    String[] v;

    public ClipArt(Context paramContext) {
        super(paramContext);
        cntx = paramContext;
        layGroup = this;

        basex = 0;
        basey = 0;
        pivx = 0;
        pivy = 0;

        mInflater = ((LayoutInflater) paramContext.getSystemService("layout_inflater"));
        mInflater.inflate(R.layout.clipart, this, true);
        btndel = ((ImageButton) findViewById(R.id.del));
        btnrot = ((ImageButton) findViewById(R.id.rotate));
        btnscl = ((ImageButton) findViewById(R.id.sacle));

        layoutParams = new RelativeLayout.LayoutParams(250, 250);
        layGroup.setLayoutParams(layoutParams);
        image = ((ImageView) findViewById(R.id.clipart));
        image.setImageResource(R.drawable.ic_launcher);

        setOnTouchListener(new View.OnTouchListener() {
            final GestureDetector gestureDetector = new GestureDetector(ClipArt.this.cntx,
                    new GestureDetector.SimpleOnGestureListener() {
                public boolean onDoubleTap(MotionEvent paramAnonymous2MotionEvent) {
                    return false;
                }
            });

            public boolean onTouch(View paramAnonymousView, MotionEvent event) {
                if (!ClipArt.this.freeze) {
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        layGroup.invalidate();
                        gestureDetector.onTouchEvent(event);

                        layGroup.performClick();
                        basex = ((int) (event.getRawX() - layoutParams.leftMargin));
                        basey = ((int) (event.getRawY() - layoutParams.topMargin));
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int i = (int) event.getRawX();
                        int j = (int) event.getRawY();
                        layBg = ((RelativeLayout) getParent());
                        if ((i - basex > -(layGroup.getWidth() * 2 / 3))
                                && (i - basex < layBg.getWidth() - layGroup.getWidth() / 3)) {
                            layoutParams.leftMargin = (i - basex);
                        }
                        if ((j - basey > -(layGroup.getHeight() * 2 / 3))
                                && (j - basey < layBg.getHeight() - layGroup.getHeight() / 3)) {
                            layoutParams.topMargin = (j - basey);
                        }
                        layoutParams.rightMargin = -1000;
                        layoutParams.bottomMargin = -1000;
                        layGroup.setLayoutParams(layoutParams);
                        break;

                    }

                    return true;
                }
                return true;
            }
        });
        this.btnscl.setOnTouchListener(new View.OnTouchListener() {
            @SuppressLint({ "NewApi" })
            public boolean onTouch(View paramAnonymousView, MotionEvent event) {
                if (!ClipArt.this.freeze) {
                    int j = (int) event.getRawX();
                    int i = (int) event.getRawY();
                    layoutParams = (RelativeLayout.LayoutParams) layGroup.getLayoutParams();
                    switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        ClipArt.this.layGroup.invalidate();
                        ClipArt.this.basex = j;
                        ClipArt.this.basey = i;
                        ClipArt.this.basew = ClipArt.this.layGroup.getWidth();
                        ClipArt.this.baseh = ClipArt.this.layGroup.getHeight();
                        int[] loaction = new int[2];
                        layGroup.getLocationOnScreen(loaction);
                        margl = layoutParams.leftMargin;
                        margt = layoutParams.topMargin;
                        break;
                    case MotionEvent.ACTION_MOVE:

                        float f2 = (float) Math.toDegrees(Math.atan2(i - ClipArt.this.basey, j - ClipArt.this.basex));
                        float f1 = f2;
                        if (f2 < 0.0F) {
                            f1 = f2 + 360.0F;
                        }
                        j -= ClipArt.this.basex;
                        int k = i - ClipArt.this.basey;
                        i = (int) (Math.sqrt(j * j + k * k)
                                * Math.cos(Math.toRadians(f1 - ClipArt.this.layGroup.getRotation())));
                        j = (int) (Math.sqrt(i * i + k * k)
                                * Math.sin(Math.toRadians(f1 - ClipArt.this.layGroup.getRotation())));
                        k = i * 2 + ClipArt.this.basew;
                        int m = j * 2 + ClipArt.this.baseh;
                        if (k > 150) {
                            layoutParams.width = k;
                            layoutParams.leftMargin = (ClipArt.this.margl - i);
                        }
                        if (m > 150) {
                            layoutParams.height = m;
                            layoutParams.topMargin = (ClipArt.this.margt - j);
                        }
                        ClipArt.this.layGroup.setLayoutParams(layoutParams);
                        ClipArt.this.layGroup.performLongClick();
                        break;
                    }
                    return true;

                }
                return ClipArt.this.freeze;
            }
        });
        this.btnrot.setOnTouchListener(new View.OnTouchListener() {
            @SuppressLint({ "NewApi" })
            public boolean onTouch(View paramAnonymousView, MotionEvent event) {
                if (!ClipArt.this.freeze) {
                    layoutParams = (RelativeLayout.LayoutParams) ClipArt.this.layGroup.getLayoutParams();
                    ClipArt.this.layBg = ((RelativeLayout) ClipArt.this.getParent());
                    int[] arrayOfInt = new int[2];
                    layBg.getLocationOnScreen(arrayOfInt);
                    int i = (int) event.getRawX() - arrayOfInt[0];
                    int j = (int) event.getRawY() - arrayOfInt[1];
                    switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        ClipArt.this.layGroup.invalidate();
                        ClipArt.this.startDegree = layGroup.getRotation();
                        ClipArt.this.pivx = (layoutParams.leftMargin + ClipArt.this.getWidth() / 2);
                        ClipArt.this.pivy = (layoutParams.topMargin + ClipArt.this.getHeight() / 2);
                        ClipArt.this.basex = (i - ClipArt.this.pivx);
                        ClipArt.this.basey = (ClipArt.this.pivy - j);
                        break;

                    case MotionEvent.ACTION_MOVE:
                        int k = ClipArt.this.pivx;
                        int m = ClipArt.this.pivy;
                        j = (int) (Math.toDegrees(Math.atan2(ClipArt.this.basey, ClipArt.this.basex))
                                - Math.toDegrees(Math.atan2(m - j, i - k)));
                        i = j;
                        if (j < 0) {
                            i = j + 360;
                        }
                        ClipArt.this.layGroup.setRotation((ClipArt.this.startDegree + i) % 360.0F);
                        break;
                    }

                    return true;
                }
                return ClipArt.this.freeze;
            }
        });
        this.btndel.setOnClickListener(new View.OnClickListener() {
            public void onClick(View paramAnonymousView) {
                if (!ClipArt.this.freeze) {
                    layBg = ((RelativeLayout) ClipArt.this.getParent());
                    layBg.performClick();
                    layBg.removeView(ClipArt.this.layGroup);
                }
            }
        });
    }


    public void disableAll() {
        this.btndel.setVisibility(4);
        this.btnrot.setVisibility(4);
        this.btnscl.setVisibility(4);
    }

    public ImageView getImageView() {
        return this.image;
    }

    public void setFreeze(boolean paramBoolean) {
        this.freeze = paramBoolean;
    }
}

布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
    <ImageButton android:id="@+id/rotate" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:adjustViewBounds="true" android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/rotation"/>
    <ImageButton android:id="@+id/sacle" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:adjustViewBounds="true" android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/pointer"/>
    <ImageButton android:id="@+id/del" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:adjustViewBounds="true" android:background="@android:color/transparent" android:scaleType="fitCenter" android:src="@drawable/close"/>
    <ImageView android:id="@+id/clipart" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"/>
    </RelativeLayout>

和图像放入可绘制

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

于 2015-10-19T05:21:46.897 回答
8

请检查 github 中的存储库我创建它。

计算从旋转和缩放视图中的中心点到推动点的距离。只需使用:

 private float getDistance(Point a, Point b) {
    float v = ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y));
    return ((int) (Math.sqrt(v) * 100)) / 100f;
}

并计算该值可以计算视图新高度和宽度的 OA/OB

计算角度AOB,A是第一个推动点,B是最后一个移动点,O是View Point的中心。

然后只需为视图设置新的高度和宽度,并计算视图的左侧和顶部。

源链接:https ://github.com/ryanch741/android-view-rotate-zoom-single-finger

编码:

    Point pushPoint;
int lastImgWidth;
int lastImgHeight;
int lastImgLeft;
int lastImgTop;
int lastImgAngle;
double lastComAngle;

int pushImgWidth;
int pushImgHeight;

int lastPushBtnLeft;
int lastPushBtnTop;

private View mView;
private Point mViewCenter;
private static final double PI = 3.14159265359;

public PushBtnTouchListener(View mView) {
    this.mView = mView;
}

private FrameLayout.LayoutParams pushBtnLP;
private FrameLayout.LayoutParams imgLP;
float lastX = -1;
float lastY = -1;

@Override
public boolean onTouch(View pushView, MotionEvent event) {
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        // 主点按下
        case MotionEvent.ACTION_DOWN:
            pushBtnLP = (FrameLayout.LayoutParams) pushView.getLayoutParams();
            imgLP = (FrameLayout.LayoutParams) mView.getLayoutParams();

            pushPoint = getPushPoint(pushBtnLP, event);
            lastImgWidth = imgLP.width;
            lastImgHeight = imgLP.height;
            lastImgLeft = imgLP.leftMargin;
            lastImgTop = imgLP.topMargin;
            lastImgAngle = (int) mView.getRotation();

            lastPushBtnLeft = pushBtnLP.leftMargin;
            lastPushBtnTop = pushBtnLP.topMargin;

            pushImgWidth = pushBtnLP.width;
            pushImgHeight = pushBtnLP.height;
            lastX = event.getRawX();
            lastY = event.getRawY();
            refreshImageCenter();
            break;
        // 副点按下
        case MotionEvent.ACTION_POINTER_DOWN:
            break;
        case MotionEvent.ACTION_UP: {
            break;
        }
        case MotionEvent.ACTION_POINTER_UP:
            break;
        case MotionEvent.ACTION_MOVE:
            float rawX = event.getRawX();
            float rawY = event.getRawY();
            if (lastX != -1) {
                if (Math.abs(rawX - lastX) < 5 && Math.abs(rawY - lastY) < 5) {
                    return false;
                }
            }
            lastX = rawX;
            lastY = rawY;

            Point O = mViewCenter, A = pushPoint, B = getPushPoint(pushBtnLP, event);
            float dOA = getDistance(O, A);
            float dOB = getDistance(O, B);
            float f = dOB / dOA;

            int newWidth = (int) (lastImgWidth * f);
            int newHeight = (int) (lastImgHeight * f);


            imgLP.leftMargin = lastImgLeft - ((newWidth - lastImgWidth) / 2);
            imgLP.topMargin = lastImgTop - ((newHeight - lastImgHeight) / 2);
            imgLP.width = newWidth;
            imgLP.height = newHeight;
            mView.setLayoutParams(imgLP);

            float fz = (((A.x - O.x) * (B.x - O.x)) + ((A.y - O.y) * (B.y - O.y)));
            float fm = dOA * dOB;
            double comAngle = (180 * Math.acos(fz / fm) / PI);
            if (Double.isNaN(comAngle)) {
                comAngle = (lastComAngle < 90 || lastComAngle > 270) ? 0 : 180;
            } else if ((B.y - O.y) * (A.x - O.x) < (A.y - O.y) * (B.x - O.x)) {
                comAngle = 360 - comAngle;
            }
            lastComAngle = comAngle;

            float angle = (float) (lastImgAngle + comAngle);
            angle = angle % 360;
            mView.setRotation(angle);
            Point imageRB = new Point(mView.getLeft() + mView.getWidth(), mView.getTop() + mView.getHeight());
            Point anglePoint = getAnglePoint(O, imageRB, angle);

            pushBtnLP.leftMargin = (int) (anglePoint.x - pushImgWidth / 2);
            pushBtnLP.topMargin = (int) (anglePoint.y - pushImgHeight / 2);
            pushView.setLayoutParams(pushBtnLP);
            break;
    }
    return false;
}

private void refreshImageCenter() {
    int x = mView.getLeft() + mView.getWidth() / 2;
    int y = mView.getTop() + mView.getHeight() / 2;
    mViewCenter = new Point(x, y);
}


private Point getPushPoint(FrameLayout.LayoutParams lp, MotionEvent event) {
    return new Point(lp.leftMargin + (int) event.getX(), lp.topMargin + (int) event.getY());
}

private float getDistance(Point a, Point b) {
    float v = ((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y));
    return ((int) (Math.sqrt(v) * 100)) / 100f;
}

private Point getAnglePoint(Point O, Point A, float angle) {
    int x, y;
    float dOA = getDistance(O, A);
    double p1 = angle * PI / 180f;
    double p2 = Math.acos((A.x - O.x) / dOA);
    x = (int) (O.x + dOA * Math.cos(p1 + p2));

    double p3 = Math.acos((A.x - O.x) / dOA);
    y = (int) (O.y + dOA * Math.sin(p1 + p3));
    return new Point(x, y);
}
于 2014-07-13T03:44:55.487 回答
1

我假设旋转/缩放发生在图像中心?在这种情况下,找到旋转角度和大小是简单的三角函数:

图片中心和手指之间形成的三角形示意图

计算手指坐标减去中心坐标的dx和。是旋转角度(以弧度为单位),可用于相对大小,或者直接将 dx/dy 加倍并直接使用。dyMath.atan2(dy, dx)Math.hypot(dx,dy)

于 2013-10-10T00:08:39.727 回答