tags:

views:

22

answers:

1

I have a ListView that I'm populating with dummy strings right now. It is currently holding 10 items, but the view itself is only large enough to show 5. So the list has to scroll of course. I've built the list using the following code:

ListView:

<RelativeLayout
    android:id="@+id/catList"
    android:layout_width="wrap_content"
    android:layout_height="216dip"
    android:layout_marginTop="120dip"
    >
    <ListView
        android:id="@+id/categoryList"
        android:layout_width="308dip"
        android:layout_height="216dip"
        android:layout_marginLeft="6dip"
        android:background="#ffffff"
        android:divider="#ffffff"
        android:choiceMode="singleChoice"
        android:cacheColorHint="#00000000"

        >
    </ListView>
    <ImageView
        android:id="@+id/catListFrame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"    
        android:layout_alignParentTop="true"
        android:src="@drawable/selectorframe"
        />
</RelativeLayout>

So basically there is an image frame around the list. This is all nested inside another layout.

I have a custom item xml file as well that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="?android:attr/listPreferredItemHeight"
   android:padding="10dip"
   android:background="#ffffff"
   >
   <TextView
       android:id="@+id/catTitle"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:textSize="20dip"
       android:textColor="#000000"
   >
   </TextView>
 </LinearLayout>

Here's the java that makes it all work:

private void setCategoryControls(){
    btnBackHome = (ImageView)findViewById(R.id.catHomeBtn);
    btnBackHome.setOnClickListener(goHome);
    catList = (ListView)findViewById(R.id.categoryList);
    catList.setOnItemClickListener(selectCat);
    demoCats = new ArrayList<String>();
    for(int i=1;i<=10;i++){
        demoCats.add("Item " + i);
    }
    m_catAdapter = new CatAdapter(this,R.layout.catitem,demoCats);
    catList.setAdapter(m_catAdapter);

}

private OnItemClickListener selectCat = new OnItemClickListener(){
    public void onItemClick(AdapterView<?> a, View v, int position, long id){
        if(selCatView!=null){
            selCatView.setBackgroundColor(Color.parseColor("#ffffff"));
        }
        v.setBackgroundColor(Color.parseColor("#ffaa00"));
        selCatView = v;
    }
};
private class CatAdapter extends ArrayAdapter<String>{

    private ArrayList<String> items;

    public CatAdapter(Context context, int textViewResourceId, ArrayList<String> items){
        super(context, textViewResourceId, items);
        this.items = items;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.catitem, null);
            }
            String cat = items.get(position);
            if (cat != null) {
                    TextView catName = (TextView) v.findViewById(R.id.catTitle);
                    if (catName != null) {
                          catName.setText(cat);
                    }

            }
            return v;
    }
}

What happens is when I click an item in the list it should simply change the background color of that item, instead it usually highlights 2 items (one that's visible and one that I have to scroll to), and most of the time it's not even the right item. Also if I scroll while an item is highlighted it will randomly change around which is highlighted as I scroll the highlighted item on and off the screen. If I had to guess, I'd say it's tied to the fact that the ListView apparantly only keeps track of the visible children. Even though it has an adapter with 10 items, if I run a getChildCount on the list view it only shows 5 or 6 depending on if one is partially visible or not, but it never shows more or less than the number of visible items.

A: 

Indeed, ListView only keeps track of the currently displayed children. This is why you recycle views in your getView method.

The simplest way to do what you are trying to achieve is to give your views a state list drawable as a background. Make an XML state list drawable with a state_pressed and a default state (and optionally a state_focused) and put that as the background drawable of your catitem. Of course you also need to remove the code that does it by hand =)

More documentation on state list drawables in here and here.

Jean
@Jean - Thanks, I'll try that. My only concern is that I will eventually need to trigger an event that takes info from the clicked item. If it is still registering the wrong item it will screw things up.
LoneWolfPR
@LoneWolfPR - Don't worry, you won't have that problem. What's happening in your example is not the click getting the wrong item: it's the drawable used by different items being shared. Since when you scroll, you use the same view, it still uses the background of a view you did click on. But you really get passed the correct list item each time.
Jean