Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rotate TextView without clipping its bounds?

I'm trying to rotate my subclass of TextView using canvas.rotate():

canvas.save();

final int w = getWidth();
final int h = getHeight();

float px = w/2f;
float py = h/2f;
canvas.rotate(mAngle, px, py);

super.draw(canvas);

canvas.restore();

TextView is rotated, however bounds of my view are clipped:

illustration

I understand that this is because of my view's size - it is not changed during rotation while it should. But if I'll change width\height in onMeasure problem will remain - I'm using LayoutParams.WRAP_CONTENT, so TextView just change it's size according to values provided in setMeasuredDimensions.

How can I solve this problem?

like image 224
Dmitry Zaytsev Avatar asked Jan 18 '13 13:01

Dmitry Zaytsev


2 Answers

I think that the entire problem here, is that you are using WRAP_CONTENT. The clip rect for the view, when you do that, is the size of the text content. The simplest way to fix the problem is to use padding. Something like this, works fine for me:

<com.example.twistedtext.TwistedTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="30dp"
    android:gravity="center"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    twistedtext:rotation="30.0f"
    android:text="@string/hello_world" />

Of course, if you do it this way, you'll have to choose a slightly different padding for each content. If you can't do that, override onMeasure, so that does exactly what TextView's onMeasure does, then adds corresponding padding, as necessary for the rotation.

Added later: Actually, this was kinda fun to figure out. I have the following onMeasure, that works pretty well:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int w = getMeasuredWidth();
    int h = getMeasuredHeight();
    w = (int) Math.round(w * cosA + h * sinA);
    h = (int) Math.round(h * cosA + w * sinA);
    setMeasuredDimension(w, h);
}

The only remaining problem is that the text gets wrapped according to the pre-rotation dimensions. You'd have to fix that too...

sinA and cosA are computed when mAngle is set.

like image 120
G. Blake Meike Avatar answered Oct 10 '22 07:10

G. Blake Meike


Ok, if you cant rotate textView in your current view hierarch, you should animate it in another one.

Create a bitmap represantation of your textView. Use a holder for this bitmap like ImageView. Connect the imageView to another layout which is on top and where it won't be cropped. Hide your textView. Run animation on ImageView. When animation finished, update textView representation, show textView and remove ImageView.

I cant find the exact code example of what you want, but take a look at this one. The interecting place is:

mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
mWindowManager.addView(YOUR_VIEW_WITH_ANIMATION, mWindowParams);
like image 29
Leonidos Avatar answered Oct 10 '22 09:10

Leonidos