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.......!
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);
}
}
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>