2012-08-19 12 views
5

Tengo un adaptador personalizado:ListView encargo Android repite fondo selección

public class PhraseCustomAdapter extends BaseAdapter 
{ 
public String original[]; 
public String translation[]; 
public String transcription[]; 

public Activity context; 
public LayoutInflater inflater; 

public PhraseCustomAdapter(Activity context,String[] original, String[] translation, String[] transcription) { 
    super(); 

    this.context = context; 
    this.original = original; 
    this.translation = translation; 
    this.transcription = transcription; 

    inflater = LayoutInflater.from(context); 
    this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
} 

@Override 
public int getCount() { 
    // TODO Auto-generated method stub 
    return original.length; 
} 

@Override 
public Object getItem(int position) { 
    // TODO Auto-generated method stub 
    return position; 
} 

public String getItemTranlation(int position) { 

    return translation[position]; 
} 

public String getItemTranscription(int position) { 
    // TODO Auto-generated method stub 
    return transcription[position]; 
} 

public String getItemOriginal(int position) { 
    // TODO Auto-generated method stub 
    return original[position]; 
} 


@Override 
public long getItemId(int position) { 
    // TODO Auto-generated method stub 
    return position; 
} 

static class ViewHolder 
{ 
    ImageView imgViewLogo; 
    TextView txtViewOriginal; 
    TextView txtViewTranslation; 
    TextView txtViewTranscription; 
} 

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

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

     holder.imgViewLogo = (ImageView) convertView.findViewById(R.id.imgViewLogo); 
     holder.txtViewOriginal = (TextView) convertView.findViewById(R.id.txtViewOriginal); 
     holder.txtViewTranslation = (TextView) convertView.findViewById(R.id.txtViewTranslation); 
     holder.txtViewTranscription = (TextView) convertView.findViewById(R.id.txtViewTranscription); 

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


    holder.txtViewOriginal.setText(original[position]); 
    holder.txtViewTranslation.setText(translation[position]); 
    holder.txtViewTranscription.setText(transcription[position]); 

    return convertView; 
} 

}

Y necesito aplicar al estilo Android4 múltiples de selección (largo prensa, a continuación, haga clic para seleccionar el elemento). Por lo tanto:

lview1 = (ListView) findViewById(R.id.listViewPhrase); 
    adapter = new PhraseCustomAdapter(this, original, translation, transcription); 
    lview1.setAdapter(adapter); 
    lview1.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); 
    lview1.setMultiChoiceModeListener(new MultiChoiceModeListener() { 

     @Override 
     public void onItemCheckedStateChanged(ActionMode mode, int position, 
               long id, boolean checked) { 
      View view; 
      if (checked){ 
       Log.v ("checked?", "YES"); 
       Log.v ("Position", Integer.toString(position)); 

       view = lview1.getChildAt(position); 
       view.setBackgroundColor(Color.LTGRAY); 


       original_list.add (adapter.getItemOriginal(position)); 
       translation_list.add (adapter.getItemTranlation(position)); 
       transcription_list.add (adapter.getItemTranscription(position)); 

       countSelected += 1; 
      } 
      if (!checked){ 
       Log.v ("checked?", "NO"); 
       Log.v ("Position", Integer.toString(position)); 


       for (int i = 0; i < original_list.size(); i++) 
       { 
        if (original_list.get(i) == adapter.getItemOriginal(position)){ 
         original_list.remove (i); 
         translation_list.remove (i); 
         transcription_list.remove (i); 
        } 
       } 
       countSelected -= 1; 
      } 


      mode.setTitle(Integer.toString(countSelected) + " " + getString(R.string.selectItem)); 
     } 

El problema es: cuando lo largo de prensa el elemento (por ejemplo, el primer elemento), el elemento séptimo se destacó también (al cambiar de fondo). Cuando trato de "desmarcar" el destacado 7º elemento, la aplicación se bloquea. Si intento hacer clic en el último elemento, la aplicación se bloquea. He leído algunos artículos acerca de cómo se procesa Vista y reciclar artículos, pero yo no conozco a ninguna posible solución para mi problema

UPD: salida LogCat cuando "unhighlighting" séptimo elemento:

V/checked?(24966): YES 
V/Position(24966): 7 
Shutting down VM 
threadid=1: thread exiting with uncaught exception (group=0x2b542210) 
AndroidRuntime(24966): FATAL EXCEPTION: main 
java.lang.NullPointerException 
at com.alextee.phrases.PhraseActivity$1.onItemCheckedStateChanged(PhraseActivity.java:145) 
at android.widget.AbsListView$MultiChoiceModeWrapper.onItemCheckedStateChanged(AbsListView.java:5688) 
at android.widget.AbsListView.performItemClick(AbsListView.java:1040) 
at android.widget.AbsListView$PerformClick.run(AbsListView.java:2522) 
at android.widget.AbsListView$1.run(AbsListView.java:3183) 
at android.os.Handler.handleCallback(Handler.java:605) 
at android.os.Handler.dispatchMessage(Handler.java:92) 
at android.os.Looper.loop(Looper.java:137) 
android.app.ActivityThread.main(ActivityThread.java:4441) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
at dalvik.system.NativeStart.main(Native Method) 
+0

Se puede publicar el StackTrace LogCat cuando ¿Tu aplicación se bloquea cuando descuelgas el 7º elemento? – tolgap

+0

Agregado al final de la publicación. –

Respuesta

10

La vista de lista es en sí misma compleja y su reciclaje también lo es. Si mira los videos del desarrollador de Android para ver la lista, sabrá más sobre el reciclaje de la vista de lista y sus problemas.
El problema en su aplicación se debe al reciclaje de la vista de lista.
Cuando cambia el fondo de un elemento de lista al hacer clic o hace clic largo, cambia el fondo y cuando este elemento se desplaza fuera del área visible de su dispositivo, la vista adjunta con este elemento se recicla y se asigna a otro elemento de la lista que está actualmente visible. Así que ahora ese artículo también se resaltará.
Este cuadro describe la vista de lista de reciclaje:

enter image description here


Para resaltar un elemento en una vista de lista que debe hacer lo siguiente:

  • Establecer onItemClickListener en la vista de lista.
  • En el método onItemClick(), cambie el fondo de la vista y guarde la posición resaltada actual en la vista de lista y llame a notifyDataSetChanged() en el adaptador de lista. Llamar a notifyDataSetChanged() es importante porque vuelve a dibujar los elementos visibles actuales.

Código de la lista onItemClick debe ser algo como esto:

grid[pos].setOnItemClickListener(new OnItemClickListener() { 
      @Override 
      public void onItemClick (AdapterView<?> parent, 
        View v, int position, long Id) 
      { 
        highlighted = position; //highlighted is a global variable 
        //container is the root view of the list row layout 
        LinearLayout container = (LinearLayout)v.findViewById(R.id.container); 
        container.setBackgroundResource(R.drawable.highlighted_backg); 
        mListAdapter.notifyDataSetChanged(); 

      } 
    }); 

El getView() método debe ser implementado de esta manera:

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

    if(convertView == null) { 
     convertView = inflater.inflate(R.layout.row_item, null); 
     holder = new ViewHolder(); 
     holder.itemName1 = (TextView)convertView.findViewById(R.id.text1); 
     ... 
     holder.container = (LineaLayout)convertView.findViewById(R.id.container); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    if(MainActivity.highlighted == position) { 
     holder.container.setBackgroundResource(R.drawable.highlighted_backg); 
    }else { 
     holder.foodItemCol1.setBackgroundResource(R.drawable.normal_back); 
    } 

    return convertView; 
} 
+0

me ayudó mucho. Gracias. –

+0

¡Excelente! la mejor respuesta muy buena! – Kay

+0

de todos modos para publicar el lcode completo? tratando de ver cómo encaja esto en mi situación actual, pero estoy un poco perdido –

1

Conjunto el color de fondo del artículo en getView() según su estado verificado. No sé si puede obtener esto directamente de ListView; de lo contrario, podría conservarlo, p. a Set y mantener allí las posiciones marcadas actualmente. Luego, en getView(), busque si la posición aprobada está en este conjunto, lo que significa que está marcada y establezca el fondo en consecuencia. De lo contrario, configure el fondo como color sin marcar. El último es importante ya que se le podría haber dado una Vista reciclada con el fondo configurado en el color 'marcado'.

Se puede encontrar un ejemplo para realizar un seguimiento de los elementos marcados here.

Cuestiones relacionadas