2011-01-03 17 views
7

Tengo un problema al cambiar el fondo de una vista en un ListView.Cambiar el fondo de ListView: comportamiento extraño

Lo que necesito:
cambiar la imagen de fondo de una fila onClick()

¿Qué sucede realmente:
El fondo se cambia (seleccionado) después de pulsar por ejemplo, la primera entrada. Pero después de desplazarse hacia abajo, también se selecciona la octava entrada. Desplazarse de nuevo a la parte superior, la primera ya no está seleccionada. La segunda entrada está seleccionada ahora. continuar desplazándose y continúa saltando ...

lo que estoy dong en el Código:
tengo canales, y onClick() i Mueva un atributo de canal booleano seleccionado y luego me cambio el fondo. Estoy haciendo esto solo onClick() Es por eso que no entiendo por qué está pasando realmente en otras entradas también. Una cosa avisos I es: Parece ser sólo el "dibujo" -parte porque el artículo que ser seleccionado "por si mismo" tiene todavía la seleccionado valor en falsa

Creo que parece tener algo que ver con la reutilización de las vistas en el ListAdapters personalizados getView (...)

Código de onClick() en 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; 
    } 

Código de 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; 
} 

Realmente agradecería cualquier idea de cómo resolver esto! :)

Si necesita más información, dígame.

¡Gracias de antemano!

Respuesta

10

Te voy a enseñar el código que utilizo para cada ListView y controlar adecuadamente el evento de clic para cambiar el fondo y hacer nada más

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; 
    } 

} 

archivo officeslistitemlayout.xml será como después de añadir estirable y diseñarlo de acuerdo con poner el siguiente código en 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> 

esperan que ayude :)

+0

Estoy en lo cierto que tal vez es sólo porque me perdí esa parte: si (posición == selectedListItem) { holder.backgrouundView.setBackgroundResource (R.drawable.and_gray_bg_listing_selected); } { demás holder.backgrouundView.setBackgroundResource (R.drawable.and_gray_bg_listing); } ? Estoy en el cajero automático, así que no puedo intentarlo ... pero lo haré tan pronto como esté en casa. Muchas gracias :) – Beasly

+1

Sí, solo necesita realizar este control en el método getView .. el resto se hará automáticamente – Javanator

+0

Usando este método podemos dibujar cualquier lista de vista muy suavemente y podemos controlar eventos adicionales también .. Usando esto incluso implementé la funcionalidad de eliminación animada de iPhone TableView ... botón rojo de eliminación y otras cosas – Javanator