Question

I have list with items having two textview and one imageview.I inflate the list with ArrayAdapter.Everything is working fine except changing list item color on click.I have 22 items in my listview. Primarily listview displaying 10 items on the screen and get the other items on scroll.Now my problem is when I clicks on a single item between 0-9(initial 10 items) item changes their color properly on click, but when i scroll and clicks on an item having position greater then 9(after the initial 10 items) my activity crashes.I am referring http://www.mail-archive.com/android-developers@googlegroups.com/msg09740.html link to write the code in for loop.Help me to get rid of this problem.Any suggestions or solutions will be highly appreciated.Thanx in advance.

 @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        //  requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); // to hide the virtual keyboard
            setContentView(R.layout.defect_pic_listview);

            try{

                adapter = new MyArrayAdapter(this,makeList());
                setListAdapter(adapter);
                adapter.notifyDataSetChanged();
                getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
                getListView().setOnItemClickListener(new OnItemClickListener() {

                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position,
                                long id) {
                        //   Toast.makeText(getApplicationContext(), "Item "+position+" is clicked",
                        //            Toast.LENGTH_SHORT).show();

                             System.out.println("position"+position);
                                int first = getListView().getFirstVisiblePosition();
                                System.out.println("first="+first);
                                int last = getListView().getLastVisiblePosition();
                                System.out.println("last="+last);
                                int total = last - first;
                                System.out.println("total="+total);
                                if(getListView().isItemChecked(position)){
                                    for(int i = 0 ; i <= last ; i++){
                                        System.out.println("i="+i);
                                        if(first+i == position){
                                            getListView().getChildAt(i).setBackgroundColor(Color.GREEN);
                                            System.out.println("l1="+getListView());
                                    //      l.getItemAtPosition(i);
                                    //      System.out.println("l position"+l);
                                        }
                                        else{
                                            getListView().getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
                                            System.out.println("l2="+getListView());
                                        }
                                    }
                                }
                                else{
                                    getListView().getChildAt(position - first).setBackgroundColor(Color.TRANSPARENT); 
                                }
                            }
                    });
            }
            catch(Exception e){
                Log.d("error",e.getMessage());
            }   
    }
Was it helpful?

Solution 5

I am giving the answer to my own question.

Here's the perfect running code:-

getListView().setOnItemClickListener(new OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position,
                        long id) {


            //   Toast.makeText(getApplicationContext(), "Item "+position+" is clicked",
                //            Toast.LENGTH_SHORT).show();

                        System.out.println("position="+position);
                        int first = getListView().getFirstVisiblePosition();
                        System.out.println("first="+first);
                        int last = getListView().getLastVisiblePosition();
                        System.out.println("last="+last);
                        int total = last - first;
                        System.out.println("total="+total);
                        if(getListView().isItemChecked(position)){
                            for(int i = first ; i <= last ; i++){
                                System.out.println("i="+i);
                                if(i == position){
                                    Log.w("TAG", "I am in If block");
                                    getListView().getChildAt(i-first).setBackgroundColor(Color.GREEN);
                                    System.out.println("l1="+getListView());
                            //      l.getItemAtPosition(i);
                            //      System.out.println("l position"+l);
                                }
                                else{

                                    getListView().getChildAt(i-first).setBackgroundColor(Color.TRANSPARENT);
                                    System.out.println("l2="+getListView());
                                }
                            }
                        }
                        else{
                            getListView().getChildAt(position).setBackgroundColor(Color.TRANSPARENT); 
                        } 
                    }

            });

OTHER TIPS

Use this code for the for loop.

if(getListView().isItemChecked(position))
{                                     
   for(int i = 0 ; i < total ; i++)
  {                                        
    System.out.println("i="+i); 
     if(first+i ==   position)
     { 
         getListView().getChildAt(i).setBackgroundColor(Color.GREEN); 
          System.out.println("l1="+getListView());
                                     //      l.getItemAtPosition(i); 
                                    //      System.out.println("l position"+l);
      }
      else
      {  
       getListView().getChildAt(i).setBackgroundColor(Color.TRANSPARENT);
       System.out.println("l2="+getListView
());
  } 
} 

I think your intention to only change the bacground color of clicked item. For that you not need to add for loop. if your intention is same as i said then use this code only at the place of for loop.

getListView().getChildAt(position).setBackgroundColor(Color.GREEN); 

There is other way to do.

First you need to add a selector xml e.g. listviewitem_bg.xml

<item android:drawable="@drawable/listview_normal" android:state_enabled="true" android:state_pressed="false"/>
<item android:drawable="@drawable/listview_press" android:state_enabled="true" android:state_pressed="true"/>

and then set it as a background of your list view cell.

You can try like this:

public class CustomAdapter extends ArrayAdapter<String> {

    String[] array;
    Context mContext;
    LayoutInflater mInflater;
    int[] itemStates;

    public CustomAdapter(Context context, int textViewResourceId,
            String[] objects)
    {
        super(context, textViewResourceId, objects);
        array=objects;
        mContext=context;
        mInflater = LayoutInflater.from(context);
        //save all buttons state as 0(not clicked) initially
        itemStates=new int[objects.length];
        for(int i=0;i<objects.length;i++)
        {
             itemStates[i]=0;
        }  
    }

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

        if(convertView==null)
        {
                 convertView = mInflater.inflate(R.layout.custom_listitem, null);
                 holder = new ViewHolder();

                 holder.text=(TextView)convertView.findViewById(R.id.text);
                 holder.layout=(LinearLayout)convertView.findViewById(R.id.linear_layout); // outer most linear layout iin custom_listitem xml
                 convertView.setTag(holder);
        }
        else
                holder=(ViewHolder)convertView.getTag();

        holder.text.setText(array[position]);

        if(itemStates[position]==0)
        {
            holder.layout.setBackgroundResource(R.drawable.red_gradient);  // item is not clicked/selected yet  
        }
        else
        {            
            holder.button.setBackgroundResource(R.drawable.green_gradient);  // item is clicked/selected so change its color        
        }       

        final int pos=position;
        holder.layout.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                itemStates[pos]=1;               
                holder.button.setBackgroundResource(R.drawable.green_gradient);                
            }
        });

        return convertView;
    }

    static class ViewHolder
    {
        TextView text;
        LinearLayout layout;
    }
}

This will give you behavior like:

  • Initially all items would be red colored.
  • if you click on 2nd item,then it will turn green(according to my code).
  • Now when you scroll and click on any other items,they will keep on turning green from red.
  • But if you click on "green" colored item,it will again turn red like it is unselected!

you can do something like this

@ outside of on create

View prevView;

then in oncreate

lv.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View view, int arg2,
                    long arg3) {
                if (prevView != null) {
                    prevView.setBackgroundColor(Color.TRANSPARENT);
                }
                view.setBackgroundColor(Color.RED);
                prevView = view;
            }
        });

A cleaner(?) solution I've successfully used is to create an extension widget of LinearLayout (or whatever root view type you use for your listitem layout) that implements Checkable.

public class CheckableLinearLayout extends LinearLayout implements Checkable {

boolean checked = false;

public CheckableLinearLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CheckableLinearLayout(Context context) {
    super(context);
}

@Override
public void setChecked(boolean checked) {

    this.checked = checked;
    updateView();


}

/* (non-Javadoc)
 * @see android.widget.Checkable#isChecked()
 */
@Override
public boolean isChecked() {
    return this.checked;
}

/* (non-Javadoc)
 * @see android.widget.Checkable#toggle()
 */
@Override
public void toggle() {
    this.checked=!this.checked;
    updateView();

}

private void updateView() {
    if (this.checked) {
                            //Change to Whatever your checked color should be, maybe expose this as attribute so i't can be changed from xml attribute
             setBackgroundResource(R.color.default_background_color);
    } else {
        setBackgroundDrawable(null);
    }
    invalidate();
}

}

Then in your item layout xml:

<my.app.widgets.CheckableLinearLayout   xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

..any views for your listitem

<my.app.widgets.CheckableLinearLayout/> 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top