rotate and resize the image view with single finger in android

后端 未结 3 1341
执笔经年
执笔经年 2020-12-29 15:22

I am developing an app which has feature that resizing and rotating the imageview by dragging its bottom right corner button.

I saw one app which has feature that if

相关标签:
3条回答
  • 2020-12-29 16:03

    I'm assuming the rotation/scaling happens from the image center? In that case, it's simple trigonometry to find the rotation angle and the size:

    Diagram of triangle formed between picture center and finger

    Calculate dx and dy of the finger's coordinates minus the center coordinates. Math.atan2(dy, dx) is the rotation angle (in radians) and Math.hypot(dx,dy) can be used for the relative size, or just double the dx/dy and use directly.

    0 讨论(0)
  • 2020-12-29 16:17

    please check the repository in github i create it .

    count the distance from center point in the rotate and zoom view to the push point. just use :

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

    and count the OA/OB that value can count the view new height and width

    count the angle AOB, the A is the first push point , the B is the last move point ,the O is the center of the View Point .

    and then just set new height and width for view ,and count the left and top for view .

    souce link : https://github.com/ryanch741/android-view-rotate-zoom-single-finger

    the code:

        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);
    }
    
    0 讨论(0)
  • I have Design A Layout that may work as your need. Download Demo here

    Java File

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

    Layout file

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

    and images put in drawable

    0 讨论(0)
提交回复
热议问题