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 version="1.0" encoding="utf-8"?>
<resources 
    xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="verticalTextStyle" 
        parent="android:Widget.TextView">
        <item name="android:padding">20dp</item>
        <item name="android:textSize">20sp</item>
    </style>
</resources>

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="text">Vertical Text</string>
    <string name="app_name">VerticalText</string>
</resources>

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

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();
	}
}

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:

    <com.stylingandroid.verticaltext.VerticalTextView
        style="@style/verticalTextStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="bottom|right"
        android:text="@string/text" />

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. This article originally appeared on Styling Android.

Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License

DeliciousStumbleUponRedditDiggBookmark/FavoritesShare

Creative Commons License
VerticalText – Part 1 by Styling Android, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. Terms and conditions beyond the scope of this license may be available at blog.stylingandroid.com.

Tags:

2 Responses to “VerticalText – Part 1”

  1. Debtaru Basak says:

    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.

Leave a Reply