9

I have a Framelayout which add four imageview at runtime as well in center it contains main image with which user can perform different action but i face the problem with rotate layout view

currently on touch of rotate button i'm doing this

public void setRotateListener() {
    mRotateImage.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            float x = event.getX(0);
            float y = event.getY(0);
            float theta = getTheta(x, y);

            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_POINTER_DOWN:
                theta_old = theta;
                break;
            case MotionEvent.ACTION_MOVE:
                float delta_theta = theta - theta_old;
                theta_old = theta;
                int direction = (delta_theta > 0) ? 1 : -1;
                angle += 3 * direction;

                Log.d("Tag", "rotate angle : " + obj.getHeight());
                obj.setRotation(angle);
                notifyListener(direction);
                break;
            }
            return true;
        }
    });
}

private float getTheta(float x, float y) {
    float sx = x - (obj.getWidth() / 2.0f);
    float sy = y - (obj.getHeight() / 2.0f);

    float length = (float) Math.sqrt(sx * sx + sy * sy);
    float nx = sx / length;
    float ny = sy / length;
    float theta = (float) Math.atan2(ny, nx);

    final float rad2deg = (float) (180.0 / Math.PI);
    float thetaDeg = theta * rad2deg;

    return (thetaDeg < 0) ? thetaDeg + 360.0f : thetaDeg;
}

but i can't get the expected result i already refer this link as well https://github.com/rprouse/XkcdClock as well as try to rotate with gesture and animation too but it seems not working as per my move on the screenwhile on touch the rotate button wants to rotate whole view in both direction clock and anticlockwise

Ajay Pandya
  • 2,417
  • 4
  • 29
  • 65
  • I can not find out how you want to rotate and what your current problem is. – mmlooloo May 15 '15 at 14:15
  • from above image you can see the rotate button on the image actually that button is added on frame dynamically so i want to rotate clock as well as anticlockwise whole frame layout, so in whatever direction user action is move on the layout, whole frame and inside image too be rotate on that direction.and my current problem is it can't rotate smooth right now in any direction.@mmlooloo – Ajay Pandya May 18 '15 at 05:56
  • Where is your frame layout on this screenshot ? does it take the whole screen or only the blue square ? what is exactly your problem ? do you manage to rotate but it isn't smooth enought ? or you don't even have any rotation ? – user2641570 May 19 '15 at 15:40
  • yah blue frame is the frame layout and i'm able to rotate on clockwise but its not smooth this is the main problem as well how to rotate anticlockwise while user move finger on that direction. – Ajay Pandya May 20 '15 at 05:29
  • Hi, you´re normalizing the values of your x and y but the `Math.atan2` needs no normalization. You just pass in the coordinates of the point and it returns angle in radians. Remove the normalization code. Now. If you take as reference the middle of the object, you should substract them from the given click coordinates and `atan2` will return the correct angle: `Math.atan2(y-y1, x-x1);` for, you see, you just need the increment in coordinates from the pivot to know the angle. – eduyayo May 20 '15 at 16:46
  • i guess this example might help you http://code.tutsplus.com/tutorials/android-sdk-creating-a-rotating-dialer--mobile-8868 – Kartheek May 21 '15 at 05:38

1 Answers1

9

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

enter image description here enter image description here enter image description here

RBK
  • 2,481
  • 2
  • 30
  • 52
  • Cannot resolve method visiball(); Actually this method is not defined anywhere. So... – User Oct 14 '15 at 05:00
  • what do you want by this method? @KhanSquare – RBK Oct 14 '15 at 05:07
  • 1
    I want to do something like you post here in your answer. So I copied your custom control in my project as you suggested. But the method visiball() is not defined anywhere, thats why I am getting an error "Cannot resolve method". and this method is called in onTouch(View paramAnonymousView, MotionEvent event) in your ClipArt class. – User Oct 14 '15 at 06:23
  • 1
    hi @KhanSquare download demo app http://ravikoradiya.com/android/StickerDemo/StickerDemo.zip – RBK Oct 16 '15 at 17:52
  • 2
    Thanks a lot man. Your demo appliaction will be very helpful for me. Thank you so much!!! – User Oct 17 '15 at 17:17
  • Dear @RBK i know this its only for single touch, but how to implement multi touch, actually i need zoom function on this ClipArt please?? – Attaullah Jul 29 '16 at 12:57
  • Awesome, This is very good tut, but please merge the Rotate and Scale button and functionality ... I tried but didn't get the accurate result. Please... and also please add the Flip functionality ... and please Add another tut for Text instead of Image ... and add the Font change functionality and Color change functionality etc.... – Zia Ur Rahman Jul 21 '17 at 11:03
  • @RBK hi nice work. Anyway your link gives 404. Can you provide a working link?. Thank you! – d91 Nov 27 '20 at 16:21
  • I have fixed 404 @d91 – RBK Nov 28 '20 at 05:52
  • @RBK Cool it works now...Thank you so much! – d91 Nov 28 '20 at 06:30