2012-02-24 4 views
5

Ancora nuovo per Android e ancor più per l'adattatore del cursore personalizzato, quindi ho difficoltà a capire come impedire che la mia listview ricicli le viste per impedire che l'input da un edittext venga visualizzato in un altro quando si scorre. Ho visto in un altro post che dice di cambiare il nome di convertview ma come farlo sto disegnando uno spazio vuoto. Speravo che qualcuno qui sarebbe stato in grado di fornire maggiori dettagli o esempi su come fare in base al codice che ho scritto finora.EditText in ListView senza il riciclaggio dell'ingresso

public class editview extends ListActivity { 
    private dbadapter mydbhelper; 
    private PopupWindow pw; 
    public static int editCount; 
    public static ListView listView; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mydbhelper = new dbadapter(this); 
     mydbhelper.open(); 


     View footer = getLayoutInflater().inflate(R.layout.footer_layout, null); 
     ListView listView = getListView(); 
     listView.addFooterView(footer); 
     showResults(); 
     } 

    //Populate view 
    private void showResults(){ 
     Cursor cursor = mydbhelper.getUserWord(); 
     startManagingCursor(cursor); 
     String[] from = new String[] {dbadapter.KEY_USERWORD}; 
     int[] to = new int[] {R.id.textType}; 
     ItemAdapter adapter = new ItemAdapter(this, R.layout.edit_row, cursor, 
         from, to); 
      adapter.notifyDataSetChanged(); 
      this.setListAdapter(adapter); 
      editCount = adapter.getCount(); 

    } 


      //footer button 
      public void onClick(View footer){ 
        final MediaPlayer editClickSound = MediaPlayer.create(this, R.raw.button50); 
        editClickSound.start(); 
        startActivity(new Intent("wanted.pro.madlibs.OUTPUT")); 

       } 

//custom cursor adapter 
class ItemAdapter extends SimpleCursorAdapter { 
    private LayoutInflater mInflater; 
    private Cursor cursor; 


    public ItemAdapter(Context context, int layout, Cursor cursor, String[] from, 
      int[] to) { 
     super(context, layout, cursor, from, to); 
     this.cursor = cursor; 
     mInflater = LayoutInflater.from(context); 

    } 


    static class ViewHolder { 
     protected TextView text; 
     protected EditText edittext; 

    } 

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


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


      holder = new ViewHolder(); 
      holder.text = (TextView) convertView.findViewById(R.id.textType); 
      holder.edittext = (EditText) convertView.findViewById(R.id.editText); 



      convertView.setTag(holder); 

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

     } 
     cursor.moveToPosition(position); 
     int label_index = cursor.getColumnIndex("userword"); 
     String label = cursor.getString(label_index); 

     holder.text.setText(label); 

     return convertView; 

    } 

} 

cambiato in

class ItemAdapter extends SimpleCursorAdapter { 
    private LayoutInflater mInflater; 
    private Cursor cursor; 
    Map<Integer, String> inputValues = new HashMap<Integer, String>(); 
    public View getView(final int position, View convertView, ViewGroup parent) { 
     .... 

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


      holder = new ViewHolder(); 
      holder.text = (TextView) convertView.findViewById(R.id.textType); 
      holder.edittext = (EditText) convertView.findViewById(R.id.editText); 


      convertView.setTag(holder); 

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

     } 
     cursor.moveToPosition(position); 
     int label_index = cursor.getColumnIndex("userword"); 
     String label = cursor.getString(label_index); 

     holder.text.setText(label); 
     String oldText = inputValues.get(position); 
     holder.edittext.setText(oldText == null ? "" : oldText); 
     holder.edittext.addTextChangedListener(new TextWatcher(){ 
      public void afterTextChanged(Editable editable) { 
       inputValues.put(position, editable.toString()); 
      } 

ma è il riciclo dopo tutto EditText disporre di dati. Ho provato a usare holder.edittext.setText (oldText) ma lo stesso effetto.

Start filling in fields

Finish filling in fields

Scroll up.

risposta

4

Prima di tutto, davvero non si vuole evitare una vista elenco dal riciclaggio delle sue vedute. Vedere il riciclaggio è un'enorme ottimizzazione. Per molte informazioni veramente buone sugli elenchi, vedi google IO talk: http://www.youtube.com/watch?v=wDBM6wVEO70

Detto questo, hai identificato correttamente il tuo problema: hai un numero di EditTexts molto inferiore rispetto a quello che fai nella tua lista. Mentre si scorre l'elenco, questi EditTex vengono riciclati in modo da visualizzare lo stesso input più e più volte.

Fondamentalmente quello che devi fare è salvare l'input per i tuoi EditTexts in qualche datastructure (un HashMap se modificano solo alcuni valori, forse un elenco se cambieranno la maggior parte dei valori, o funzionerebbe) che mappa la posizione sull'input. Si può fare questo con l'aggiunta di un textChangedListener per la modifica dei testi in GetView:

@Override 
public View getView(final int position, View convertView, ViewGroup parent){ 
    ... 
    cursor.moveToPosition(position); 
    int label_index = cursor.getColumnIndex("userword"); 
    String label = cursor.getString(label_index); 

    holder.text.setText(label); 

    //clear whatever text was there from some other position 
    //and set it to whatever text the user edited for the current 
    //position if available 
    String oldText = yourMapOfPositionsToValues.get(position); 
    holder.setText(oldText == null ? "" : oldText); 

    //every time the user adds/removes a character from the edit text, save 
    //the current value of the edit text to retrieve later 
    holder.edittext.addTextChangedListener(new TextWatcher(){ 
     @Override 
     public void afterTextChanged(Editable editable) { 
      yourMapOfPositionsToValues.put(position, editable.toString()); 
     } 
     .... 
    }; 

    return convertView; 
} 

Ogni volta che l'utente è fatto l'editing, è possibile eseguire attraverso il vostro datastructure e fare tutto ciò con quei valori.

Edit:

ho cambiato OnTextChanged a afterTextChanged perché ho usato quella prima e so che funziona. Tieni presente che afterTextChanged viene chiamato ogni volta che un LETTER cambia, non solo dopo che l'utente ha finito di digitare una parola. Se l'utente digita "cane" dopoTextChanged sarà chiamato tre volte, prima con 'd', poi con 'do', quindi con 'dog'.

Un HashMap è semplice: Map yourMapOfPositionsToValues ​​= new HashMap();

per aggiungere o aggiornare un elemento: yourMap.put (posizione, someText); per recuperare un oggetto: yourMap.get (posizione);

se le hashmap non hanno senso, passa un po 'di tempo a ricercarle. Sono una struttura di dati incredibilmente importante.

L'implementazione di TextWatcher non è corretta. La tua struttura dati non dovrebbe appartenere a una singola vista, ma piuttosto l'attività o l'adattatore. Ti sembra che le posizioni non siano stabili perché il tuo elenco è di proprietà di ciascuna vista. Le posizioni stesse sono stabili in quanto, a meno che i dati sottostanti non cambiano, il cursore restituirà sempre gli stessi dati per la stessa posizione. Tuttavia, il testo di modifica viene utilizzato per più posizioni diverse.

Creare una hashmap come variabile di istanza che ho dimostrato sopra nel costruttore dell'adattatore. Quindi aggiungi esattamente il TextWatcher che ho scritto in origine, non c'è bisogno di una classe con nome, l'anonimo è più semplice. Il tuo codice dovrebbe funzionare.

+0

Stavo giocando con aftertextchange ma ho scoperto che non stava memorizzando i valori come volevo. IE memorizzerebbe solo parte della stringa in diverse parti della matrice. Potrei digitare qualcosa come dog nell'ultimo edittext e quando chiamerei le posizioni in ArrayList editTextList. Sembrerebbe pos1 cane pos2 do pos3 do. Non capivo perché si limitasse ad afferrare parte della stringa edittext. – maebe

+0

Le posizioni sembravano inaffidabili ma forse le stavo definendo male. Quando usavo un adattatore per semplice cursore, ho cambiato l'id di edittext via per loop e usavo quel ciclo per archiviarlo e chiamarli alla prossima attività. Ma ha ancora incontrato problemi di riciclaggio. Ho esaminato le hashmap ininterrottamente per le ultime due settimane, ma non riesco a trovare alcuna buona informazione che spieghi come usarle. Solo pezzi di codice qua e là. – maebe

+0

// TextWatcher, salva i dati nell'array per un uso successivo. implementatore di classi implementa TextWatcher { posizione int privata; osservatore pubblico (posizione int) { this.position = position; } \t public void afterTextChanged (s modificabile) { \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t Log.e (String.valueOf (posizione), "è la posizione di int") ; \t Testo stringa = s.toString(); \t editview.editTextList.add (posizione, testo); È quello che mi è venuto in mente con il mio textwatcher – maebe

1

La soluzione è rimuovere il textwatcher aggiunto prima di impostare il testo. Altrimenti, il precedente visualizzatore di testo su quella vista sarà ancora chiamato insieme al nuovo textwatcher. Salva il textwatcher come tag su EditText per tenerne traccia.

Object oldWatcher = viewHolder.quantitySold.getTag(); 
    if(oldWatcher != null){ 
     viewHolder.quantitySold.removeTextChangedListener((CustomTextWatcher)oldWatcher); 
    } 
    String oldText = inputValues.get("key"+position); 
    Log.d(TAG, "oldText: "+oldText+" position: "+position); 
    viewHolder.quantitySold.setText(oldText == null ? "" : oldText); 
    CustomTextWatcher watcher = new CustomTextWatcher(
      cursor.getString(SKUFragment.COL_NAME), 
      cursor.getInt(SKUFragment.COL_ID), 
      cursor.getDouble(SKUFragment.COL_UNIT_PRICE), 
      position 
    ) { 
     @Override 
     public void beforeTextChanged(CharSequence s, int start, int count, int after) { 

     } 

     @Override 
     public void onTextChanged(CharSequence s, int start, int before, int count) { 

     } 

     @Override 
     public void afterTextChanged(Editable s) { 
      if (s != null) { 
       int quantity = 0; 
       if (!TextUtils.isEmpty(s.toString())) { 
        quantity = Integer.parseInt(s.toString()); 
        inputValues.put("key"+mPosition, "" + quantity); 
       }else{ 
        inputValues.put("key"+mPosition, ""); 
       } 
       double value = quantity * skuPrice; 
       mListener.onQuantityChanged(skuName+", position: "+mPosition, skuId, quantity, value); 
      } 
     } 
    }; 
    viewHolder.quantitySold.setTag(watcher); 
    viewHolder.quantitySold.addTextChangedListener(watcher);