Align top of image to top of TextView
I want to create a layout that aligns the top of an image to the top of a TextView like this:
--------- Text text text text text text text
| Image | text text text text text text text
--------- text text text text text text text
text text text text text text text
text text text text text.
I tried doing this by setting android:drawableLeft
to my image, but that centers the image vertically:
Text text text text text text text
--------- text text text text text text text
| Image | text text text text text text text
--------- text text text text text text text
text text text text text.
Is this possible with just a TextView or do I need to create a RelativeLayout containing a TextView and an ImageView?
Here is the XML layout for my TextView that gives the incorrect layout:
<TextView
android:gravity="top"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/image"
android:drawablePadding="8dp"
android:text="@string/text" />
The android:gravity="top"
attribute only seems to affect the text, not the drawable.
Solution 1:
You can align a compound-Drawable to the top (or bottom) by creating a custom Drawable that wraps your Drawable, and then manipulate the drawing of your custom Drawable by overriding the method onDraw(Canvas)
.
The sample below is the simplest possible example. This aligns the image to the top, but you can also make it align to the bottom, left or right of the TextView by implementing the required logic in the onDraw(Canvas)
-method. You might also want to build in a margin in the onDraw(Canvas)
, to make your design implementation pixel perfect.
Sample usage:
GravityCompoundDrawable gravityDrawable = new GravityCompoundDrawable(innerDrawable);
// NOTE: next 2 lines are important!
innerDrawable.setBounds(0, 0, innerDrawable.getIntrinsicWidth(), innerDrawable.getIntrinsicHeight());
gravityDrawable.setBounds(0, 0, innerDrawable.getIntrinsicWidth(), innerDrawable.getIntrinsicHeight());
mTextView.setCompoundDrawables(gravityDrawable, null, null, null);
Sample code:
public class GravityCompoundDrawable extends Drawable {
// inner Drawable
private final Drawable mDrawable;
public GravityCompoundDrawable(Drawable drawable) {
mDrawable = drawable;
}
@Override
public int getIntrinsicWidth() {
return mDrawable.getIntrinsicWidth();
}
@Override
public int getIntrinsicHeight() {
return mDrawable.getIntrinsicHeight();
}
@Override
public void draw(Canvas canvas) {
int halfCanvas= canvas.getHeight() / 2;
int halfDrawable = mDrawable.getIntrinsicHeight() / 2;
// align to top
canvas.save();
canvas.translate(0, -halfCanvas + halfDrawable);
mDrawable.draw(canvas);
canvas.restore();
}
}
Solution 2:
Try to USe RelativeLayout......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="@drawable/ic_launcher" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/imageView1"
android:text="@string/text" />
</RelativeLayout>
Solution 3:
I think, there's an easier and faster way than have 3 views. You need to prepare proper 9patch for icon and then use FrameLayout. It's even possible to have only single EditText
/ TextView
using the same drawable as their background. More details are described in this answer.