Sonntag, 6. März 2011

ListView in Android: TextView und EditText in einer Zeile

Android 2.3.1 Wenn mann aus einem xml-File eine längere Liste von Strings zu Controls auf der Oberfläche verarbeinen will, ist ListView ein geeignetes Mittel, soll nur ein Control pro Zeile vorhanden sein ist der Aufwand wie hier beschrieben minimal.

Sollen mehrere Controls pro Zeile vorhanden sein wird es etwas mehr Aufwand, aus verschiedenen Quellen im Netz hab ich mir soetwas zusammengebaut, ich stelle es nun hier vor:

Die Activity:
public class InputPropertiesActivity extends DefaultListActivity {
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.inputproperties);

  final List rowHolders = new ArrayList();
  String[] rowNames = getResources().getStringArray(R.array.properties);
  for (int i = 0; i < rowNames.length; i++) {
   RowHolder talentholder = new RowHolder(rowNames[i], "");
   rowHolders.add(talentholder);
  }
  setListAdapter(new MyListAdapter(this, R.layout.listrow, rowHolders));
 }
}


Bei der DefaultListActivity handelt es sich nur um eine Klasse die ListActivity extended und ein paar Methoden beinhalted, die ich in allen ListActivities zur Verfügung haben will. Im Prinzip lese ich hier nur mein xml aus und stopfe die Werte zusammen mit einem Leerstring in ein RowHolder Array, das ich meinen MyListAdapter übergebe, den ich dann als ListAdapter festlege.

Der RowHolder:
public class RowHolder {
 String rowName;
 String rowValue;

 public RowHolder(String talentName, String talentValue) {
  this.rowName = talentName;
  this.rowValue = talentValue;
 }

 public String getRowName() {
  return rowName;
 }

 public void setRowName(String rowName) {
  this.rowName = rowName;
 }

 public String getRowValue() {
  return rowValue;
 }

 public void setRowValue(String rowValue) {
  this.rowValue = rowValue;
 }
}


Der ListAdapter:
public class MyListAdapter extends BaseAdapter {

 private final List rowholders;
 private final int rowResID;
 private final LayoutInflater layoutInflater;

 public MyListAdapter(final Context context, final int rowResID, final List rowHolder) {
  this.rowResID = rowResID;
  this.rowholders = rowHolder;

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

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

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

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

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

  final ViewHolder viewHolder;
  final RowHolder rowholder;

  if (convertView == null) {
   viewHolder = new ViewHolder();
   rowholder = rowholders.get(position);
   convertView = layoutInflater.inflate(rowResID, null);
   viewHolder.rowName = (TextView) convertView.findViewById(R.id.rowname);
   viewHolder.rowName.setText(rowholder.getRowValue());


   viewHolder.rowValue = (EditText) convertView.findViewById(R.id.rowvalue);
   viewHolder.rowValue.addTextChangedListener(new TextWatcher() {
    public void afterTextChanged(Editable edit) {
     rowholders.get(viewHolder.ref).setRowValue(edit.toString());
    }

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

    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
    }
   });
   convertView.setTag(viewHolder);
  } else {
   viewHolder = (ViewHolder) convertView.getTag();
  }

  viewHolder.ref = position;
  viewHolder.rowName.setText(rowholders.get(position).getRowName());
  viewHolder.rowValue.setText(rowholders.get(position).getRowValue());
  return convertView;
 }

 class ViewHolder {
  TextView rowName;
  EditText rowValue;
  int ref;
 }
}


Der Aufwand, der hier betrieben wird, ist schon etwas mehr als wenn nur ein Element pro Zeile vorhanden wäre. Allerdings läßt sich obiges wiederverwenden, sind also viele Ansichten ähnlich, müssen aber aus verschiedenen xml´s befüllt werden, nutzt man es einfach nochmal.

Dazu das vereinfachte inputproperties.xml aus dem layout Folder (Die Darstellung der Groß- und Kleinschreibung haut leider so gar nicht hin, muß beim kopieren entsprechend geändert werden):


 
  
  
 



Und das listrow.xml aus dem layout Folder:


 
  
  
 



Wie aber bekommt man die Werte nun wieder raus, wenn ich sie zB. persistieren will? Hierzu habe ich mich wieder des ListAdapters bedient:

Methode saveProperties() der Klasse InputPropertiesActivity:
public void saveProperiets() {

  for (int i = 0; i < this.getListAdapter().getCount(); i++) {
   String rowName = ((RowHolder) this.getListAdapter().getItem(i)).getRowName();
   String rowValue = ((RowHolder) this.getListAdapter().getItem(i)).getRowValue();

   Log.d("NAME - VALUE:", rowName + " " + rowValue);
   if (rowValue == null || rowValue.equalsIgnoreCase("")) {
    showDialog(DIALOG_PROPERTY_MISSING_ID);
   } else {
    inputTalents();
   }
  }
 }


Das Ergebnis (inklusive einiger Modifikationen, mit obigen Code wurde nur die Liste erzeugt) sieht dann so aus, wobei die Anzahl der Elemente beliebig ist:


Links:
Problemstellung zu dieser Konstellation

Keine Kommentare:

Kommentar veröffentlichen