Anfängerproblem

E

eddie7

Neues Mitglied
0
Hi,

ich habe ein Beispiel aus Beginning Android modfifiziert, um eine ListView mit EditText zu kreieren. Es soll lediglich eine Liste mit einem Text und einem editierbaren Feld pro Zeile angezeigt werden.

Leider hab ich da noch ein paar Verständnisprobleme, die mich schon einge Stunden quälen. :)
Das Original hatte statt dem EditText eine RatingBar und funktioniert einwandfrei. Meine Version sieht ok aus, bis ich anfange zu scrollen. Dann kommen die angezeigten Werte durcheinander.
Beim Debuggen sehe ich, dass getView im AusgabenWrapper beim Scrollen nach unten eine View übergeben bekommt, wenn man den sichtbaren Bereich verlässt, obwohl da meiner Meinung nach noch keine existieren dürfte, und von da ab ist alles durcheinander.

Da das ein bißchen unverständlich sein dürfte, ist unten der Code.

Wäre für nen Tipp, was ich da falsch mache, wirklich dankbar. Auch ein RTFM mit link zu einem passenden Beispiel wäre hilfreich, ich habe schon nach Beispielen gegoogled, aber nichts Passenderes gefunden.
Bin ziemlich unerfahren, was Oberflächenprogrammierung (sprich MVC) angeht.
Ich vermute, dass die Lösung ganz trivial ist..

Ach ja, die 2. Frage:
wenn ich in diesem Beispiel in ein EditText klicke,verliere ich erst mal den Focus, wenn die Tastatur aufgeht und muss noch mal reinklicken, um editieren zu können. Dass ich nicht editieren kann, ist höchstwahrscheinlich eine Folge des obigen Problems mit getView.


Viele Grüße,
Eddie

AusgabenWrapper.java
Code:
package com.commonsware.android.fancylists.seven;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListAdapter;

public class AusgabenWrapper extends AdapterWrapper {
    Context ctxt=null;
    String[] rates=null;
    
    public AusgabenWrapper(Context ctxt, ListAdapter delegate) {
        super(delegate);
        
        this.ctxt=ctxt;
        this.rates=new String[delegate.getCount()];
        
        for (int i=0;i<delegate.getCount();i++) {
            this.rates[i]=(String) getItem(i);
        }
    }
    
    public View getView(int position, View convertView,
                                            ViewGroup parent) {
        ViewWrapper wrap=null;
        View row=convertView;
                                                        
        if (convertView==null) {
            LinearLayout layout=new LinearLayout(ctxt);
            EditText editText=new EditText(ctxt);
            
            editText.setTag(new Integer(position));
            editText.setText(rates[position]);
            
            View guts=delegate.getView(position, null, parent);
        
            layout.setOrientation(LinearLayout.HORIZONTAL); 
                    
            editText.setLayoutParams(new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.WRAP_CONTENT,
                        LinearLayout.LayoutParams.FILL_PARENT));
            guts.setLayoutParams(new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT,
                        LinearLayout.LayoutParams.FILL_PARENT));
            
                    
            layout.addView(editText);                     
            layout.addView(guts);
            
            wrap=new ViewWrapper(layout);
            wrap.setGuts(guts);
            layout.setTag(wrap);
            
            row=layout;                
        }
        else {
            wrap=(ViewWrapper)convertView.getTag();
            wrap.setGuts(delegate.getView(position, wrap.getGuts(), parent));
        }
        
        return(row);
    }        
}
ViewWrapper.java:
Code:
package com.commonsware.android.fancylists.seven;

import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;

class ViewWrapper {
    ViewGroup base;
    View guts=null;
    EditText rate=null;
    
    ViewWrapper(ViewGroup base) {
        this.base=base;
    }
    
    EditText getText() {
        if (rate==null) {
            rate=(EditText)base.getChildAt(0);
        }
        
        return(rate);
    }
    
    void setEditText(EditText rate) {
        this.rate=rate;
    }
    
    View getGuts() {
        if (guts==null) {
            guts=base.getChildAt(1);
        }
        
        return(guts);
    }
    
    void setGuts(View guts) {
        this.guts=guts;
    }
}
AusgabenListView.java:
Code:
/***
    Copyright (c) 2008-2009 CommonsWare, LLC
    
    Licensed under the Apache License, Version 2.0 (the "License"); you may
    not use this file except in compliance with the License. You may obtain
    a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

package com.commonsware.android.fancylists.seven;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListAdapter;
import android.widget.ListView;

public class AusgabenListView extends ListView {
    public AusgabenListView(Context context) {
        super(context);
    }
    
    public AusgabenListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
                                    
    public AusgabenListView(Context context, AttributeSet attrs,
                                                int defStyle) {
        super(context, attrs, defStyle);
    }
    
    public void setAdapter(ListAdapter adapter) {
        super.setAdapter(new AusgabenWrapper(getContext(), adapter));
    }
}
Ausgaben.java:
Code:
package com.commonsware.android.fancylists.seven;

import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;

public class Ausgaben extends ListActivity {
    String[] items={"null", "eins", "zwei", "drei", "vier", "fünf",
                    "sechs", "sieben", "acht", "neun", "zehn",
                    "elf", "zwölf", "dreizehn", "vierzehn", "fünfzehn",
                    "sechzehn", "siebzehn", "achtzehn", "neunzehn", "zwanzig"};
    
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        
        setListAdapter(new ArrayAdapter<String>(this,
                                                android.R.layout.simple_list_item_1,
                                                items));
    }
}
AdapterWrapper.java:
Code:
package com.commonsware.android.fancylists.seven;

import android.database.DataSetObserver;
import android.widget.ListAdapter;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;

public class AdapterWrapper implements ListAdapter {
    ListAdapter delegate=null;
    
    public AdapterWrapper(ListAdapter delegate) {
        this.delegate=delegate;
    }
    
    public int getCount() {
        return(delegate.getCount());
    }
    
    public Object getItem(int position) {
        return(delegate.getItem(position));
    }
    
    public long getItemId(int position) {
        return(delegate.getItemId(position));
    }
    
    public View getView(int position, View convertView,
                                            ViewGroup parent) {
        return(delegate.getView(position, convertView, parent));
    }
    
    public void registerDataSetObserver(DataSetObserver observer) {
        delegate.registerDataSetObserver(observer);
    }
    
    public boolean hasStableIds() {
        return(delegate.hasStableIds());
    }
    
    public boolean isEmpty() {
        return(delegate.isEmpty());
    }
    
    public int getViewTypeCount() {
        return(delegate.getViewTypeCount());
    }
    
    public int getItemViewType(int position) {
        return(delegate.getItemViewType(position));
    }
    
    public void unregisterDataSetObserver(DataSetObserver observer) {
        delegate.unregisterDataSetObserver(observer);
    }
    
    public boolean areAllItemsEnabled() {
        return(delegate.areAllItemsEnabled());
    }
    
    public boolean isEnabled(int position) {
        return(delegate.isEnabled(position));
    }
}
main.xml:
Code:
<?xml version="1.0" encoding="utf-8"?>
<com.commonsware.android.fancylists.seven.AusgabenListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/list"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:drawSelectorOnTop="false"
/>
AndroidManifest.xml:
Code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.commonsware.android.fancylists.seven">
        <application android:label="@string/app_name"
                android:icon="@drawable/cw">
                <activity android:name=".Ausgaben" android:label="@string/app_name">
                        <intent-filter>
                                <action android:name="android.intent.action.MAIN" />
                                <category android:name="android.intent.category.LAUNCHER" />
                        </intent-filter>
                </activity>
        </application>
</manifest>
 
Hallo,

gerne helfe ich!

Reduziere dein Problem mal :D. Wenn ich kann antworte ich!:thumbsup:

Grüße Bobert
 
Reduzieren - das hab ich befürchtet. :)

Im Code kann ich nichts weglassen, da ich mir nicht sicher bin, wo das Problem ist. Ich versuche aber mal, das Problem zu beschreiben.

Ich will nur eine Liste anzeigen, die pro Zeile ein EditText und ein TextView enthält, befüllt aus einem array von Strings.
Das sieht beim Programmstart auch ganz gut aus. Wenn ich aber scrolle, ist der Inhalt ab der 9. zeile im EditText falsch, in der TextView richtig. Da kommt irgenwas durcheinander.
Was mich verwirrt, ist, dass getView in AusgabenWrapper für die falsch dargestellten Zeilen bereits beim 1. Aufruf eine View (convertView) erhält, obwohl da meiner Meinung nach noch keine View dafür da sein dürfte - für die ersten 8 Zeilen wird beim ersten Aufruf von getView korrekt null (keine View) geliefert. Oder verstehe ich da getView falsch?
Die Inhalte der EditText-Felder ab der 9. Zeile sind identisch mit denen ab der 1. Zeile (10. = 2. usw.). Wenn ich dann wieder nach oben scrolle, sind die Inhalte der EditText-Komponenten total durcheinander.

Ich hoffe, ich habe mich einigermaßen verständlich ausgedrückt...

Viele Grüße,
Eddie
 
EditTexte in ner ListView.. damit hatte ich mich auch mal rumgeschlagen.. hab dann letztendlich auf ScrollView umgestellt.
Bin auf ne Lösung gespannt. :)
 
Hier meine Lösung (zusammengebastelt aus verschiedenen Codeschnipseln im Netz):

Die Klasse, die die Werte hält:
Code:
public class Ausgabe {
  String item;
  String betrag;
    
    Ausgabe(String item, String betrag) {
    this.item = item;
    this.betrag = betrag;
    }

  public String getItem() {
    return item;
  }

  public void setItem(String item) {
    this.item = item;
  }

  public String getBetrag() {
    return betrag;
  }

  public void setBetrag(String betrag) {
    this.betrag = betrag;
  }
}
Die Activity:
Code:
public class Eingabe extends ListActivity {
  String[] items =
      { "null", "eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun", "zehn", "elf", "zwölf",
          "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24" };

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.ausgaben_overview);

    final List<Ausgabe> ausgaben = new ArrayList<Ausgabe>();
    for (int i = 0; i < items.length; i++) {
      Ausgabe ausgabe = new Ausgabe(items[i], items[i] + "Test");
      ausgaben.add(ausgabe);
    }

    setListAdapter(new AusgabenAdapter(this, R.layout.eintrag, ausgaben));
  }
}
Der abgeleitete Adapter:
Code:
public class AusgabenAdapter extends BaseAdapter {
  private final Context context;
  private final List<Ausgabe> ausgaben;
  private final int rowResID;
  private final LayoutInflater layoutInflater;

  public AusgabenAdapter(final Context context, final int rowResID, final List<Ausgabe> ausgaben) {
    this.context = context;
    this.rowResID = rowResID;
    this.ausgaben = ausgaben;

    layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }

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

  public Object getItem(int position) {
    return ausgaben.get(position);
  }

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

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

    final ViewHolder viewHolder;
    final Ausgabe ausgabe;

    if (convertView == null) {
      viewHolder = new ViewHolder();
      ausgabe = ausgaben.get(position);
      convertView = layoutInflater.inflate(rowResID, null);
      viewHolder.item = (EditText) convertView.findViewById(R.id.item);
      viewHolder.item.addTextChangedListener(new TextWatcher() {
        public void afterTextChanged(Editable edit) {
          ausgaben.get(viewHolder.ref).setItem(edit.toString());
        }

        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        }

        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
          // attitude_values[ref] = Attitude_Value.getText().toString();
        }
      });

      viewHolder.betrag = (TextView) convertView.findViewById(R.id.betrag);
      viewHolder.betrag.setText(ausgabe.getBetrag());
      convertView.setTag(viewHolder);
    } else {
      viewHolder = (ViewHolder) convertView.getTag();
    }

    viewHolder.ref = position;
    viewHolder.item.setText(ausgaben.get(position).getItem());
    viewHolder.betrag.setText(ausgaben.get(position).getBetrag());
    return convertView;
  }

  class ViewHolder {
      TextView betrag;
      EditText item; 
      int ref;
  }
}

Das Problem war: ListView hält nicht so viele Einträge, wie es darzustellende Daten gibt. Deswegen werden views wiederverwendet und müssen mit korrekten Daten gesetzt werden. Die richtigen Daten werden anhand der position bestimmt und in ref im ViewHolder gehalten. Geänderte Daten werden mit einem TextWatcher gesichert.

Vielleicht hilfts ja jemandem...

Gruß,
Eddie
 

Ähnliche Themen

M
Antworten
5
Aufrufe
790
madgnoll
M
I
Antworten
2
Aufrufe
822
IngoNoehr
I
D
Antworten
8
Aufrufe
1.007
Vacutainer
Vacutainer
Zurück
Oben Unten