Showing posts with label ListView. Show all posts
Showing posts with label ListView. Show all posts

Sunday, October 17, 2010

Fancy List Items in a ListView

A while ago, I was working on a project where I wanted to be able to have Android show a ListView, with custom entries in the list. In most other languages and toolkits, doing this is a bit of a pain. You have to implement a special painter to pain the list cell in just the right way. Unless you are a pretty die-hard developer for that toolkit you may find yourself horribly confused as to how to handle the situation.

Fortunately, Android made this REALLY easy. If you know how to do a layout for a form, you know almost everything you need to know in order to make a fancy list item.

First, you want to create a small layout that specifies how a single list entry should look. For my purposes, I wanted to have a single line of large text, with smaller text below. I also wanted the large text to be bright white, and the smaller text to be a darker gray color. Finally, the smaller text should be indented on both sides to indicate that it is subordinate to the larger text.

No problem! A basic linear layout will do the job nicely. My final layout looks like this :


<linearlayout android="http://schemas.android.com/apk/res/android" layout_height="wrap_content" layout_width="fill_parent" orientation="vertical">
<textview layout_height="wrap_content" id="@+id/LargeText" text="Large Text" textcolor="@color/white" textsize="25dip" layout_width="fill_parent"></textview>
<textview layout_height="wrap_content" layout_width="fill_parent" layout_marginright="10dip" layout_marginleft="10dip" id="@+id/SmallText" text="Smaller Text" textcolor="#c0c0c0"></textview>
</linearlayout>


Easy enough. Now that we have that, we need to actually write some code that will use it. I find it easiest to create a convenience class that lets me manipulate the list easily. So, I create a class called MultiLineList, that looks something like this :


import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.widget.SimpleAdapter;

public class MultiLineList {

private ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
private Activity parentActivity;
private SimpleAdapter taskAdapter;

public MultiLineList(Activity parent)
{
parentActivity = parent;

taskAdapter = new SimpleAdapter(parentActivity, list,
R.layout.multi_item_layout, new String[] { "largetext","smalltext" },
new int[] { R.id.LargeText, R.id.SmallText } );
}

public void clear()
{
list.clear();
}

public void addItem(String largeText, String smallText)
{
HashMap<String,String> item = new HashMap<String,String>();
item.put("largetext", largeText);
item.put("smalltext", smallText);
list.add(item);
}

public SimpleAdapter getData()
{
return taskAdapter;
}
}


In the constructor, we create a SimpleAdapter that we use to map our text in to the different rows of the list view we will show the user. "R.layout.multi_item_layout" is the name of the layout we created above. (You may need to change this if you called your layout something else.) The two strings, followed by the two ints give us a mapping in a hash table for how to identify the two different TextEdits that we put in the layout. There is nothing special about only having two items. We could easily have 10 strings and 10 matching ints. What is important is that each string has a corresponding int that maps to a text edit in your layout.

The addItem() method is where the good stuff happens. As part of creating the SimpleAdapter in the constructor, we told it to use the "list" variable to get its data out of. So, the addItem() method allows us to easily put new text in to the list to be used. So, calling addItem("I am big", "I am not") would give us a single entry in the list view that contained the text "I am big" in the large font, and "I am not" in the small font.

Now that we have all of the ground work in place, it is time to put the pieces together. Moving forward, I am going to assume that you have a basic form set up with a list view configured in it. Also, that a ListView variable points to it called "listView". From there, using our fancy list widgets would look something like this :


myList = new MultiLineList(this);
myList.addItem("Large 1", "Small 1");
myList.addItem("Large 2", "Small 2");

listView.setAdapter(myList.getData());



Now, the next time out list view is drawn, it will contain two items in the list. The first one will have "Large 1" in the larger text, and "Small 1" in the smaller text. The second one will contain "Large 2" in the larger text, and "Small 2" in the smaller text.

From this simple example, you should be able to easily expand your list items to contain any just about any widget type you would want. But, I leave that up to you to experiment with.

Wednesday, June 9, 2010

Something simple. Get text from a ListView.

Perhaps this topic is considered too simple for most people, which is why there aren't more postings about it. But, it seems like a useful thing to know. Specifically, when you are using a ListView with the android.R.layout.simple_list_item_1 view, how the heck do you get the text from the item clicked in the OnItemClickListener class?

It is pretty simple. The second parameter of the onItemClick is a View that contains just the item that was clicked. (Or tapped, whatever.) If you used Eclipse to automagically generate the callback method for you, the variable will be named "arg1", which is what we will assume for this example.

Inside of the onItemClick method, you can figure out the text using the following code :

String s = ((TextView)arg1.findViewById(android.R.id.text1)).getText().toString();


Pretty simple, huh? But, the code doesn't quite explain itself. So, I'll take a stab at it.

A ListView is exactly what the name says. It is a list of views. When you create the ArrayAdapter that you will use to display the data, you also tell the ArrayAdapter what view it should use. In our case, we chose "android.R.layout.simple_list_item_1" so we could use a simple array for the data. What we are doing is referencing a very simple layout that only displays a single line of text. I am sure if you Google around you can find the XML definition.

Inside the layout is a single definition. It is a TextView named "text1". Since it is a built-in layout, we will find the layout information under "android.R", instead of just "R" where our layout definitions show up.

So, by executing findViewById() on the view that was clicked, and passed in as "arg1", we can get the text that the user clicked on.

Pretty simple huh?

Monday, May 17, 2010

Stupid Android ListView tricks

I recently made some major changes to the Movie Track app that I put out. What started as an app that I did for my own use seems to have gained a few users. So, I decided to upgrade the look and feel a bit. In the process of this, I changed several of the screens from using a ListActivity to using a normal XML layout that contained a ListView. After mucking around with all of the settings to get things looking the way I wanted, I ran in to an interesting snag.

Everything displayed the way I wanted it to, but to "click" on an item that was in the ListView, you had to actually "click" on the text of the ListView, and not just on the row in the ListView. Perhaps I am a perfectionist at some level, but this annoyed me to no end.

Much Google later, I couldn't find the answer on how to do it. So, I started to mess with settings. A hair-brained idea or two later, I decided to try changing the ListView's layout-width from "wrap_content" to "fill_parent". Amazingly enough, that did exactly what I wanted!

Sure, this was a bit of a "duh" experience, and a newbie mistake. But, I figured I would publish it here in case some other developer runs across the same thing, and gets as frustrated as I was getting!