Android fastest drawing layout for a list row - android

I'm creating a list view that I want to scroll smoothly.
I am currently designing the row in my XML file, and am wondering which layout view to choose. I want a row layout similar to this:
Mine will have an ImageView on the left, then two rows of TextView's on top of each other. (The orb on that picture isn't needed)
So what is the most efficient (when it comes to drawing) layout to use? Options I'm considering are TableLayout, RelativeLayout and LinearLayout (horizontal).
Extra info:
My list adapter is already very efficient and uses the viewholder pattern as well as pre-computation of TextView textand other optimisations to get maximum efficiency there. This question was specifically about the layout of the list row, though your help is appreciated!

I suggest you to use a RelativeLayout so you can choose where to place every single component. Basically, on the left side the imageview, then 2 textview one above the other. Optionally, the image on the right side.
<?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="100dip"
android:padding="3dip" >
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/icon" />
<TextView
android:id="#+id/first_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/image"
android:layout_toRightOf="#+id/image"
android:textSize="30dp"
android:textColor="#ffffff"
android:text="Medium Text" />
<TextView
android:id="#+id/second_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/first_txt"
android:layout_below="#+id/first_txt"
android:textSize="20dp"
android:textColor="#0481ab"
android:text="Small Text"/>
<ImageView
android:id="#+id/right_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#drawable/icon" />
</RelativeLayout>

You can try to:
Use a Spannable for showing all text as markup in one TextView.
The image(?) on right can be set as a right CompoundDrawable for the above TextView.
Set android:drawingCacheQuality="low" if you don't have fancy gradients in background.
Don't do something heavy in Adapter's getView(), if you did Override it.

Related

How can I use RelativeLayout to align buttons to the right of an ImageView

I'm struggling with a simple relative layout. It is supposed to have an image on the left and a column of other views on the right. The vertical alignment is correct but the horizontal alignment is very puzzling with the buttons on the left of the image even though I have asked for them to be on the right.
Can anyone explain:
why this happens,
how to achieve the arrangement I want.
Here is the layout xml and a screenshot:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/widget51"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="#+id/ivLove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_centerHorizontal="true"
/>
<TextView
android:id="#+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:hint="Image name"
android:layout_toRightOf="#+id/ivImage"
/>
<TextView
android:id="#+id/tvPage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Page URL"
android:layout_below="#+id/tvDate"
android:layout_toRightOf="#+id/ivImage"
/>
<Button
android:id="#+id/btnNext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Next"
android:layout_below="#+id/tvPage"
android:layout_toRightOf="#+id/ivImage"
/>
<Button
android:id="#+id/btnPrevious"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Previous"
android:layout_below="#+id/btnNext"
android:layout_toRightOf="#+id/ivImage"
/>
</RelativeLayout>
In case you are wondering about the image see Android : Simple HTML parsing & image downloader using AsyncTask
You are putting those controls (TextView, Button) on the right side of the ImageView with id ivImage.
However, your layout does not contain any ImageView with that id (but has one with ivLove).
The controls appear on the left because that's the default docking for views inside a RelativeLayout.
Try updating your references (replace each "ivImage" with "ivLove".
Note -- if you use Eclipse, that the reason you didn't get compile errors for this is that you probably have an ImageView with android:id="ivImage" somewhere in your project. Enabling (and maybe updating) lint will help you filter these kinds of issues.

Reusing, and Editing child view's properties of Custom View

My goal is to mimic the app list page of Google's Play Store.
to do that, I have made a Relative view for each app box which contains icon, title, developer, etc...
<RelativeLayout
android:layout_width="205px"
android:layout_height="310px"
android:background="#FFFFFF"
android:padding="10px"
android:layout_margin="4px">
<ImageView
android:id="#+id/icon1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:layout_marginTop="5px"
android:layout_marginLeft="5px"
android:layout_marginRight="5px"
android:layout_marginBottom="20px"
android:src="#drawable/icon1" />
<TextView
android:layout_below="#id/icon1"
android:id="#+id/title1"
android:text="#string/t1"
android:gravity="left"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#333333"
android:textSize="20px" />
<TextView
android:layout_below="#id/title1"
android:text="#string/company"
android:gravity="left"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#555555"
android:textSize="15px" />
</RelativeLayout>
I want to put 72 different app boxes in a big scroll view but that requires thousands of lines..
I know I can reuse custom view with but I have know idea how to change the properties of sub-level view(child view). (like Image src of the code above.)
Is there anyway to shorten the line or reuse the custom view?
Or.. Is there a easier way to make 72 different app boxes?
You'll want to use a GridView or ListView, and an ArrayAdapter inflated with the above layout. It's rather hard to help you any further until you investigate this route.
GridView Information
ListView Information
Adapter Information

Placing text view over an image view using FrameLayout

Below is how I have designed my xml. Now what I am trying to fit a textview inside the white box shown below. But am being restricted by FrameLayout (at least I think so) that I need to hard code values to make the text view fit in the middle or some where inside the white box. I cannot use Relative or other layouts for this purpose as I have understood by my trials as this whole is a single image.
Here is my layout,
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:visibility="visible" android:layout_marginTop="60dip"
android:layout_gravity="center" android:id="#+id/xxx">
<ImageView android:id="#+id/calloutquizImage"
android:background="#drawable/callout" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:scaleType="fitCenter" />
<ImageView android:id="#+id/triviaImage"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_alignTop="#+id/calloutquizImage" android:layout_gravity="left"
android:src="#drawable/trivia" android:background="#drawable/trivia"
android:layout_marginTop="50dip" android:layout_marginLeft="85dip"></ImageView>
<TextView android:text="TextView" android:id="#+id/triviAnswerText"
android:layout_marginTop="125dip" android:layout_marginLeft="85dip"
android:layout_gravity="left" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:textColor="#000000"
android:typeface="sans"></TextView>
<ImageButton android:id="#+id/triviaanswercloseButton"
android:src="#drawable/closebtn" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:background="#drawable/closebtn"
android:layout_marginRight="8dip" android:layout_marginTop="43dip"
android:layout_gravity="right" android:onClick="triviaanswerClose"></ImageButton>
<ImageView android:id="#+id/buttontoclose"
android:layout_gravity="left"
android:visibility="visible" android:onClick="triviaanswerClose"
android:layout_marginTop="50dip" android:layout_marginLeft="75dip"
android:layout_width="230dip" android:layout_height="170dip"></ImageView>
</FrameLayout>
Because of this the text view looks in different positions in various handsets.
Any guesses what can be done for this instead?
Below is my image :
I think you are not doing the right thing. If you want a text to appear inside a white box (or even resize it, if there is to many text to fit to it) - you can still avoid any layouts ad do it with only one TextView.
Please have a look what is NinePatch image in Android:
http://developer.android.com/reference/android/graphics/NinePatch.html
http://developer.android.com/tools/help/draw9patch.html - drawing tools
So basically you will need only 1 textView and your image, properly converted to 9-patch with 2nd link. (Basically - just add a few black pixels on image border).
No just set this 9-patch as a background of textView. It will place text right where you need, and will shrink white box if you'll define so in 9-patch.
UPD:
Please find the resulting screenshot:
As you can see, textView not handles
WhiteBox" itself, filling it with text and resizing the box if necessary.
Here is how to make it work:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/first"
android:background="#drawable/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Manymanymany text
Manymanymany text
Manymanymany text
Manymanymany text
Manymanymany text
Manymanymany text" />
<TextView
android:layout_below="#+id/first"
android:background="#drawable/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Not so many text" />
</RelativeLayout>
And here is your image, converted to 9patch. Just place it to "drawable/" folder. Note: it MUST have "back.9.png" name.
For details of how 9patch works you can check links above. The main idea: by making black dots on left and top border - you specify which part of the image will be stretched when image must be upscaled. By making dots on right/bottom side you tell the View where to place the content. In our case content is a text of the TextView.
Hope it helps, good luck
I think you can use a RelativeLayout within the FrameLayout for the ImageView and the TextView, and by using the parameters, you can navigate the TextView to the white box. Refer to the LayoutParams documentation for details.
for eg. you can add the ImageView block first and then the TextView, so that the TextView will lay over the ImageView, and by using align bottom, and specifying top margin with a negative value, you can make the TextView go over the image. Or rather, if you are using eclipse, you can directly move the text view in the graphic layout.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools"
android:id="#+id/xxx"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="0dp"
android:visibility="visible" >
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margintop="0dp" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/user2" />
<TextView
android:id="#+id/Textviewtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world"
android:layout_below="#+id/imageView1"
android:layout_marginTop="-10dp"
app:context=".TestActivity" />
</RelativeLayout>
</FrameLayout>
Similar to above, you can specify margin left and right to properly position your TextView as you want. Check with graphic layout for feedback to know the correct position.
Please reply if this helped.
Use your images and values for the height and width. I just tried for testing.

Why are my "centered" objects slightly off-center in my RelativeLayout?

I wanted to make two equally-sized radio buttons with a custom background, text, and an image to the right of the text. Because of how different these are from a standard "Button", I made them using a clickable "RelativeLayout".
The text and the image are of different heights, but I want each one to be centered vertically in the button. I also want the combination of the text+image to be centered horizontally in the button. This second part is what I'm having trouble with; it's off-center, close to the left side. In the image below, the left side is what I want, but the right side is what's happening. The image on one of the buttons (the one with the longer text) is resized to be smaller, too... Though there is still plenty of space on the right side of the button.
Here is my code:
<LinearLayout
android:baselineAligned="false"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RelativeLayout
android:id="#+id/my_button"
android:background="#drawable/radio_button"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<TextView
android:id="#+id/button_textview"
android:text="#string/button_label"
android:textAppearance="?android:attr/textAppearanceButton"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
<ImageView
android:contentDescription="#string/image_description"
android:id="#+id/button_imageview"
android:layout_centerVertical="true"
android:src="#drawable/my_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/button_textview">
</ImageView>
</RelativeLayout>
<RelativeLayout
... same thing for the second button ...
</RelativeLayout>
</LinearLayout>
What am I doing wrong?
Use this as your button:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="MyButton"/>
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="#drawable/my_image"/>
</LinearLayout>
Now, you can place it in other parent views. To apply layout attributes to above button, place those attributes in the outer <LinearLayout> tag of above button.
Alternative:
You can set custom images to be drawn on sides(Left,Right,Top,Bottom) of a TextView using attributes like:
android:drawableLeft="#drawable/my_image"
Turns out the solution was adding
android:paddingRight="0dip"
strangely enough, even though I didn't put any padding there in the first place.

How do I vertically align an item within a list using relative layout?

I am using a list view in Android 1.5 to show a list of images and text next to the image. I am trying to vertically center the text but the text is at the top of the row instead of centered. Below is my layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/row"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip">
<ImageView android:id="#+id/item_image" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:paddingRight="10dip"
android:src="#drawable/default_image" android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"/>
<TextView android:id="#+id/item_title"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_toRightOf="#id/item_image"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"
/>
</RelativeLayout>
It seems strange that I need to set alignParentTop="true" when I'm trying to vertically center the text, but if I don't the text does not even show up. What am I doing wrong?
EDIT following the comments:
It turns out making this work with RelativeLayout isn't easy. At the bottom of the answer I've included a RelativeLayout that gives the effect wanted, but only until it's included in a ListView. After that, the same problems as described in the question occurred. This was fixed by instead using LinearLayout(s).
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:orientation="horizontal">
<ImageView android:id="#+id/pickImageImage"
android:layout_width="100dp"
android:layout_height="80dp"
android:background="#drawable/icon"
android:scaleType="fitXY"
android:layout_marginRight="10dp"/>
<TextView android:id="#+id/pickImageText"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:gravity="left|center_vertical"
android:text="I'm the text"/>
</LinearLayout>
If you want to have two text boxes, you can nest a second orientation="vertical" and LinearLayout after the ImageView and then put the text boxes in there.
This works, but I have to admit I don't know why the RelativeLayouts didn't. For example, this blog post by Romain Guy specifically says that the RelativeLayout should. When I tried it, I never got it to quite work; admittedly I didn't do it exactly as he did, but my only changes were with some attributes of the TextViews, which shouldn't have made that much of a difference.
Here's the original answer:
I think you're confusing Android with all those somewhat contradictory instructions in RelativeLayout. I reformatted your thing to this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/row"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip">
<ImageView android:id="#+id/item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="10dip"
android:src="#drawable/icon"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"/>
<TextView android:id="#+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/item_image"
android:layout_centerVertical="true"
android:text="Blah!"/>
</RelativeLayout>
And that works fine. I removed many of your redundant android:layout_alignParentxxx because they weren't necessary. This view now comes up with the picture in the top left corner and the text vertically centered next to it. If you want the picture vertically centered as well, then you can't have the RelativeLayout be on android:layout_height="wrap_content" because it's trying to make itself no taller than the height of the picture. You'd have to specify a height, e.g. 80dp, and then set the ImageView to a fixed height like 60dp with android:scaleType="fitXY" to make it scale down to fit properly.
Was stuck on a similar issue for a while, but found this from CommonsWare:
"When you inflate the layout, use inflate(R.layout.whatever, parent, false), where parent is the ListView."
Works but only when you set the height of the row to a specific value (ie you can't use wrap_content).
Baseline directive would do it, but ImageView simply does not support baseline alignment as of today. You can work around this by creating a subclass of ImageView, override the getBaseline() method and return the height of the image.

Categories

Resources