Text

VerticalText – Part 1

Recently I was working on a project where I had free reign over the UI, and felt that it would be very nice to have some vertically oriented text. On searching through the Android API docs, I found that rotating Views isn’t supported directly, but a quick Google search found a number of approaches. In this article we’ll explore a couple of different methods for displaying vertical text in Android.

Before we begin, let’s discuss what I was trying to achieve. I wanted the text rotated through 90 degrees anti-clockwise. To achieve this we need to move our text to the right by a distance equal to its own height, down by a distance equal to its own width, and then rotate it by -90 around its bottom left corner. So, if we start with the following text:

Original Text
Original Text

We want this to appear as follows:

Final Text
Final Text

As I have often said on this blog: There are usually multiple was of achieving your desired results on Android, and this case is no different.

Let’s start by creating a new 4.0.3 project with minSdk=”1.6″ named VerticalText, with a package name of com.stylingandroid.verticaltext, and a default activity named VerticalTextActivity.

Next, we’ll create a style in res/values/styles.xml which we’l use later:

[xml]


[/xml]

Next we’ll replace the default string named hello with one named text to res/values/strings.xml:

[xml]

Vertical Text
VerticalText

[/xml]

We’re now ready to look at how we achieve the rotation of the text that we require. The first option that I found was on StackOverflow where a user named “mice” outlined a custom control to display rotated text. Let’s create a new class named VerticalTextView which is an exact copy of mice’s solution

[java] public class VerticalTextView extends TextView
{
final boolean topDown;

public VerticalTextView( Context context,
AttributeSet attrs )
{
super( context, attrs );
final int gravity = getGravity();
if ( Gravity.isVertical( gravity )
&& ( gravity & Gravity.VERTICAL_GRAVITY_MASK )
== Gravity.BOTTOM )
{
setGravity(
( gravity & Gravity.HORIZONTAL_GRAVITY_MASK )
| Gravity.TOP );
topDown = false;
}
else
{
topDown = true;
}
}

@Override
protected void onMeasure( int widthMeasureSpec,
int heightMeasureSpec )
{
super.onMeasure( heightMeasureSpec,
widthMeasureSpec );
setMeasuredDimension( getMeasuredHeight(),
getMeasuredWidth() );
}

@Override
protected void onDraw( Canvas canvas )
{
TextPaint textPaint = getPaint();
textPaint.setColor( getCurrentTextColor() );
textPaint.drawableState = getDrawableState();

canvas.save();

if ( topDown )
{
canvas.translate( getWidth(), 0 );
canvas.rotate( 90 );
}
else
{
canvas.translate( 0, getHeight() );
canvas.rotate( -90 );
}

canvas.translate( getCompoundPaddingLeft(),
getExtendedPaddingTop() );

getLayout().draw( canvas );
canvas.restore();
}
}
[/java]

This is quite straightforward. In the constructor it is tweaking the gravity of the underlying TextView to switch the orientation of the gravity to match the rotation of the text. It overrides the onMeasure() method to swap the width and height of the control to match the final dimensions of the rotated text. Finally it overrides onDraw() and applies a rotation dependent on the gravity setting.

We can now change our main layout in res/layout/main.xml to include a VerticalTextView control:

[xml]
[/xml]

We are using the style and string values that we defined earlier, and we need to set the gravity to bottom|right in order to get the text in the orientation that we want. Please feel free to have a play with different values here to explore how the gravity affects things.

If we run this, we get the desired result:

Rotated Text
Rotated Text

This works quite nicely but, as mice says in his answer, it does have certain limitations such as handling marquees. There are also some other similar approaches in other answers to the same question, but they all have certain limitations of one kind or another. I’m not going to bother explaining them all here because they are all variations upon the same concept of creating a custom control.

In the concluding part of this series we’ll look at another method which uses a standard TextView control and doesn’t break any of its functionality.

The source code for this article can be found here.

© 2012, Mark Allison. All rights reserved.

Copyright © 2012 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

6 Comments

  1. I am trying to rotate a Listview clockwise/anticlockwise and the listitem which is in the middle of the 90 deg should be in the focus.
    I am only using one fourth of the screen(quarter of a circle) where if I do a clockwise or anticlockwise gesture the listview should also rotate and the middle item should be in focus.
    Could you pls give me some pointers how to implement it?
    A code example would be more helpful.

  2. In second approach:
    After rotation, this still leaves a lot of space on the right side, ie more the text, more empty space on the right will be there. Try putting another view on the right of this TextView.
    Any solutions for that.

    Thanks

  3. FYI:
    With Ref to my earlier comment, regarding empty space on the right; the first approach works better in that respect at-least.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.