Is there any way to rotate a button without using

2019-04-30 04:56发布

问题:

I am in search of methodology for rotating a button. without using animations..!

I don't want use animations because of this.

if any body has any idea please help me.

xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent" android:id="@+id/ll" android:gravity="center_vertical">
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello" />
    <com.mind.RotateButton android:layout_width="100dp"  android:gravity="center_vertical"
        android:layout_height="100dp" android:id="@+id/ll1">
    <Button android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:text="Button" android:id="@+id/but" />
    </com.mind.RotateButton>
</LinearLayout>

code

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);      
        Button btn   = (Button) findViewById(R.id.but);     
        btn.setOnClickListener(new OnClickListener() {          
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "Hello", Toast.LENGTH_SHORT).show();                
            }
        });
    }

Thanks in advance.......!

回答1:

extend Button class:

public class RotateButton extends Button{

    public RotateButton(Context context) {
        super(context);
    }

    public RotateButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.rotate(45, getWidth() / 2, getHeight() / 2);
        super.onDraw(canvas);
        canvas.restore();
    }

}

and in your layout:

<com.samples.myapp.ui.RotateButton
        android:layout_height="wrap_content" android:id="@+id/MyBtn"
        android:padding="5dip" android:textColor="@color/darkGreen"
        android:textSize="16dip" android:text="TextView"
        android:layout_width="wrap_content"></com.samples.myapp.ui.RotateButton>

----------------------------------------------------------------------

edit:

Another approach: design a rotatable LinearLayout and put your controls in it. LinearLayout can be rotated completely:

package org.mabna.order.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class RotateLinearLayout extends LinearLayout{

    private Matrix mForward = new Matrix();
    private Matrix mReverse = new Matrix();
    private float[] mTemp = new float[2];

    public RotateLinearLayout(Context context) {
        super(context);
    }

    public RotateLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {

        canvas.rotate(180, getWidth() / 2, getHeight() / 2);

        mForward = canvas.getMatrix();
        mForward.invert(mReverse);
        canvas.save();
        canvas.setMatrix(mForward); // This is the matrix we need to use for
                                    // proper positioning of touch events
        super.dispatchDraw(canvas);
        canvas.restore();
        invalidate();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        event.setLocation(getWidth() - event.getX(), getHeight() - event.getY());
        return super.dispatchTouchEvent(event);
    }
}


回答2:

Using ideas from breceivemail answer I made rotate layout that actually works. It's designed to hold single view, it will dispatch touch events correctly but no padding or margins are supported in this realization. Also it's only supports angles like 90, 180, 270 etc. Layout size will just match the size of it's child after rotation.

public class RotateLayout extends ViewGroup {

    public static class LayoutParams extends ViewGroup.LayoutParams {

        public int angle;

        public LayoutParams(Context context, AttributeSet attrs) {
            super(context, attrs);
            final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RotateLayout_Layout);
            angle = a.getInt(R.styleable.RotateLayout_Layout_layout_angle, 0);
        }

        public LayoutParams(ViewGroup.LayoutParams layoutParams) {
            super(layoutParams);
        }

    }

    public RotateLayout(Context context) {
        super(context);
    }

    public RotateLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setWillNotDraw(false);
    }

    public View getView() {
        return view;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        view = getChildAt(0);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
        if(angle != layoutParams.angle) {
            angle = layoutParams.angle;
            angleChanged = true;
        }

        if(Math.abs(angle % 180) == 90) {
            measureChild(view, heightMeasureSpec, widthMeasureSpec);
            setMeasuredDimension(
                resolveSize(view.getMeasuredHeight(), widthMeasureSpec), 
                resolveSize(view.getMeasuredWidth(), heightMeasureSpec));
        }
        else {
            measureChild(view, widthMeasureSpec, heightMeasureSpec);
            setMeasuredDimension(
                resolveSize(view.getMeasuredWidth(), widthMeasureSpec), 
                resolveSize(view.getMeasuredHeight(), heightMeasureSpec));
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if(changed || angleChanged) {
            layoutRectF.set(0, 0, r - l, b - t);
            layoutTransitionMatrix.setRotate(angle, layoutRectF.centerX(), layoutRectF.centerY());
            layoutTransitionMatrix.mapRect(layoutRectFRotated, layoutRectF);
            layoutRectFRotated.round(viewRectRotated);
            angleChanged = false;
        }

        view.layout(viewRectRotated.left, viewRectRotated.top, viewRectRotated.right, viewRectRotated.bottom);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();
        canvas.rotate(-angle, getWidth() / 2f, getHeight() / 2f);
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        invalidate();
        return super.invalidateChildInParent(location, dirty);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        touchPoint[0] = event.getX();
        touchPoint[1] = event.getY();

        layoutTransitionMatrix.mapPoints(childTouchPoint, touchPoint);
        event.setLocation(childTouchPoint[0], childTouchPoint[1]);
        return super.dispatchTouchEvent(event);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new RotateLayout.LayoutParams(getContext(), attrs);
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams layoutParams) {
        return layoutParams instanceof RotateLayout.LayoutParams;
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams layoutParams) {
        return new RotateLayout.LayoutParams(layoutParams);
    }

    private View view;
    private int angle;

    private final Matrix layoutTransitionMatrix = new Matrix();

    private final Rect viewRectRotated = new Rect();

    private final RectF layoutRectF = new RectF();
    private final RectF layoutRectFRotated = new RectF();

    private final float[] touchPoint = new float[2];
    private final float[] childTouchPoint = new float[2];

    private boolean angleChanged = true;

}

attrs.xml (add this file to res/values folder)

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="RotateLayout_Layout">
        <attr name="layout_angle" format="integer"  />
    </declare-styleable>

</resources>

Usage example:

<com.you.package.name.RotateLayout
    xmlns:app="http://schemas.android.com/apk/res/com.you.package.name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_angle="-90"
        android:text="Rotated Button"/>
</com.you.package.name.RotateLayout>