Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change ListView background - strange behaviour

I have a problem with changing the background of a view in a ListView.

What I need:
Change the background image of a row onClick()

What actually happens:
The background gets changed (selected) after pressing e.g. the first entry. But after scrolling down the 8th entry is selected too. Scroll back to the top the first isn't selected anymore. The second entry is selected now. Continue scrolling and it continues jumping...

What i'm dong in the Code:
I have channels, and onClick() I toggle an attribute of channel boolean selected and then I change the background. I'm doing this only onClick() thats why I don't get why it's actuelly happening on other entries too. One thing I notices is: It seems to be only the "drawing"-part because the item which get selected "by it self" has still the selected value on false

I think it seems to have something to do with the reuse of the views in the custom ListAdapters getView(...)

Code of onClick() in ListActivity:

@Override
    protected ViewHolder createHolder(View v) {

        // createHolder will be called only as long, as the ListView is not
        // filled

        TextView title = (TextView) v
                .findViewById(R.id.tv_title_channel_list_adapter);
        TextView content = (TextView) v
                .findViewById(R.id.tv_content_channel_list_adapter);

        ImageView icon = (ImageView) v
                .findViewById(R.id.icon_channel_list_adapter);

        if (title == null || content == null || icon == null) {
            Log.e("ERROR on findViewById",
                    "Couldn't find Title, Content or Icon");
        }
        ViewHolder mvh = new MyViewHolder(title, content, icon);

        // We make the views become clickable
        // so, it is not necessary to use the android:clickable attribute in
        // XML

        v.setOnClickListener(new ChannelListAdapter.OnClickListener(mvh) {

            public void onClick(View v, ViewHolder viewHolder) {
                // we toggle the enabled state and also switch the the
                // background
                MyViewHolder mvh = (MyViewHolder) viewHolder;
                Channel ch = (Channel) mvh.data;
                ch.setSelected(!ch.getSelected()); // toggle

                if (ch.getSelected()) {
                    v.setBackgroundResource(R.drawable.row_blue_selected);
                } else {
                    v.setBackgroundResource(R.drawable.row_blue);
                }
                // TESTING
                Log.d("onClick() Channel", "onClick() Channel: "
                        + ch.getTitle() + " selected: " + ch.getSelected());
            }
        });
return mvh;
    }

Code of getView(...):

@Override
public View getView(int position, View view, ViewGroup parent) {
    ViewHolder holder;

    // When view is not null, we can reuse it directly, there is no need
    // to reinflate it.
    // We only inflate a new View when the view supplied by ListView is
    // null.
    if (view == null) {
        view = mInflater.inflate(mViewId, null);

        // call own implementation
        holder = createHolder(view);

        // TEST
        // we set the holder as tag
        view.setTag(holder);

    } else {
        // get holder back...much faster than inflate
        holder = (ViewHolder) view.getTag();
    }

    // we must update the object's reference
    holder.data = getItem(position);

            // <EDIT SOLUTION>

    if(getItem(position).get_id() == channelList.get(position).get_id()){
        if(getItem(position).getSelected())
        {
            view.setBackgroundResource(R.drawable.row_blue_selected);
        }
        else{
            view.setBackgroundResource(R.drawable.row_blue);
        }
    }

            // </EDIT SOLUTION>

    // call the own implementation
    bindHolder(holder);

    return view;
}

I really would appreciate any idea how to solve this! :)

If more information is needed please tell me.

Thanks in advance!

like image 855
Beasly Avatar asked Jan 03 '11 09:01

Beasly


1 Answers

Let me show you the code that I use for every ListView and properly controlling the click event for changing the background and doing anything further

public class Offices extends Activity {

    private ListView listView;

    /* selectedListItem will contain the number of items to be selected.
     * Your list item OnOlickListener will simply change this variable
     * to the position of the clicked item. The Adapter will do the rest 
     * because you need to refresh the ListView.
     */ 
    private int selectedListItem = -1;
    private Handler mHandler = new Handler();
    private Vector<String> data; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.officeslayout);
        data = new Vector<String>();

        // Add data as per your requirement   
        data.add("one");
        data.add("two");
        data.add("three");
        data.add("four");
        data.add("Five");
        data.add("Six");
        data.add("Seven");
        data.add("Eight");
        data.add("Nine");
        data.add("Ten");

        listView = (ListView)findViewById(R.id.ListView01);
        listView.setDivider(null);

        listView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {

                selectedListItem = position;
                ((EfficientAdapter)listView.getAdapter()).notifyDataSetChanged();

                mHandler.postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        // call any new activity here or do any thing you want here         

                    }
               }, 200L);
            }
        });

        listView.setAdapter(new EfficientAdapter(getApplicationContext()));   
    }

    private class EfficientAdapter extends BaseAdapter {
        private LayoutInflater mInflater;

        public EfficientAdapter(Context context) {
            mInflater = LayoutInflater.from(context);
        }

        public int getCount() {
            return data.size();
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder;

            if (convertView == null || convertView.getTag() == null) {
                convertView = mInflater.inflate(R.layout.officeslistitemlayout, null);
                holder = new ViewHolder();
                holder.backgroundView = (ImageView) convertView
                    .findViewById(R.id.OfficesBackground);
                holder.officesTitle = (TextView) convertView
                    .findViewById(R.id.OfficesName);

                convertView.setTag(holder);
            } else {
                 holder = (ViewHolder) convertView.getTag();
            }

            if(position == selectedListItem) {  
                 holder.backgroundView.setBackgroundResource(R.drawable.and_gray_bg_listing_selected);
            } else {
                 holder.backgroundView.setBackgroundResource(R.drawable.and_gray_bg_listing);
            }

            holder.officesTitle.setText(data.get(position)); 

            return convertView;
        }
    }

    static class ViewHolder {
        TextView officesTitle;
        ImageView backgroundView;
    }

}

officeslistitemlayout.xml file will be like following add drawable and design it according to you put the following code in RelativeLayout

 <ImageView android:id="@+id/OfficesBackground" android:layout_width="fill_parent"       
            android:layout_height="45dip"
            android:layout_alignParentTop="true"   
            android:background="@drawable/and_gray_bg_listing"
            android:scaleType="fitXY"
            ></ImageView>


         <TextView android:id="@+id/OfficesName" android:layout_width="wrap_content" 
                   android:text="Offices Name" 
                   android:textColor="#000000" android:textStyle="bold"  
                   android:layout_height="wrap_content"
                   android:layout_centerVertical="true" android:layout_marginLeft="5dip"
            ></TextView>

Hope it will help :)

like image 148
Rohit Sharma Avatar answered Sep 22 '22 21:09

Rohit Sharma