CheckBox im ExpandableListView zum Ein- und Ausblenden einzelner Spalten funktioniert nicht immer

  • Antworten:9
  • Bentwortet
Philip M.
  • Forum-Beiträge: 90

18.01.2012, 13:07:02 via Website

Moin zusammen,

ich versuch nun schon seit zwei Tagen mir einen ExpandableListView zusammen zu basteln in welchem ich auf Konopdruck einen Eintrag rausnehmen kann. Es handelt sich hierbei um eine CheckBox mit der Beschriftung "Liefer- und Rechnungsadresse identisch". Wenn diese CheckBox aktiviert ist, soll die Vie für die Rechnungsadresse nicht angezeigt werden. Das ganze funktioniert nun auch wunderbar bis auf ein paar kleinere Fehler, nämlich das die oberste View in welcher die CheckBox ist (die für die Lieferadresse) manchmal einige Klicks nicht entgegen nimmt. Allerdings nur bei CheckBoxen und RadioButtons, bei Textfeldern funktioniert alles immer tadellos.

Ich poste euch mal ein bisschen Quellcode dazu und hoffe das mir hierbei jemand helfen kann, ich weiß nämlich nicht mehr woran dasl iegen könnte. =/


Das hier ist die CheckBox welche dafür zuständig sein wird das die Rechnungsadressen-View ausgeblendet wird
1private LinearLayout getSameAdressCheckbox(ViewGroup parent) {
2 if(sameAdressCheckBox == null) {
3 checkBoxLayout = new LinearLayout(parent.getContext(), null);
4 checkBoxLayout.setFocusable(false);
5 checkBoxLayout.setFocusableInTouchMode(false);
6 checkBoxLayout.setLayoutParams(new LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
7 checkBoxLayout.setWeightSum(1.0f);
8 checkBoxLayout.setPadding(0, (int)(2 * parent.getResources().getDisplayMetrics().density + 0.5f), 0, (int)(2 * parent.getResources().getDisplayMetrics().density + 0.5f));
9 sameAdressCheckBox = new CheckBox(parent.getContext());
10 sameAdressCheckBox.setText("Liefer- und Rechnungsadresse sind identisch");
11 sameAdressCheckBox.setBackgroundColor(0xFFFFFFFF);
12 sameAdressCheckBox.setTextColor(0xFF000000);
13 sameAdressCheckBox.setTextSize(TypedValue.COMPLEX_UNIT_PT, 5);
14 sameAdressCheckBox.setButtonDrawable(R.drawable.check_box_selector_1);
15 LinearLayout.LayoutParams lp = new LayoutParams(0, LinearLayout.LayoutParams.FILL_PARENT);
16 lp.setMargins((int)(10 * parent.getResources().getDisplayMetrics().density + 0.5f), 0,0,0);
17 lp.weight = 1;
18 sameAdressCheckBox.setLayoutParams(lp);
19 sameAdressCheckBox.setPadding((int)(20 * parent.getResources().getDisplayMetrics().density + 0.5f), (int)(10 * parent.getResources().getDisplayMetrics().density + 0.5f), (int)(5 * parent.getResources().getDisplayMetrics().density + 0.5f), (int)(10 * parent.getResources().getDisplayMetrics().density + 0.5f));
20 sameAdressCheckBox.setClickable(true);
21 sameAdressCheckBox.setFocusable(false);
22 sameAdressCheckBox.setFocusableInTouchMode(false);
23
24 sameAdressCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
25
26 @Override
27 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
28 sameAdressCheckBox.setChecked(isChecked);
29 if(listener != null)
30 listener.onSameAdressClicked(isChecked);
31
32 }
33 });
34 isAdressSame = sameAdressCheckBox.isChecked();
35
36 checkBoxLayout.addView(sameAdressCheckBox);
37 }
38
39
40 return checkBoxLayout;
41 }

Hier überschreibe ich die Methode getGroupCount(), da wenn ich eine Gruppe ausblende (die für die Rechnungsadresse), gibt es ja logischerweise eine Gruppe weniger
1@Override
2 public int getGroupCount() {
3 if(isAdressSame())
4 return super.getGroupCount() - 1;
5 else
6 return super.getGroupCount();
7 }

Hier überschreibe ich nun die Methode getGroupView() damit ich auch für die einzelnen Gruppen trotzdem noch die richtige Überschrift erhalte, auch wenn mitten drin eine View nun fehlt
1@Override
2 public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
3 View v;
4 switch (groupPosition) {
5 case 0:
6 isFirstExpanded = isExpanded;
7 break;
8 case 1:
9 if(isAdressSame()) {
10 isThirdExpanded = isExpanded;
11 v = super.getGroupView(groupPosition+1, isThirdExpanded, convertView, parent);
12 } else {
13 isSecondExpanded = isExpanded;
14 v = super.getGroupView(groupPosition, isSecondExpanded, convertView, parent);
15 }
16 v.setFocusable(false);
17 v.setFocusableInTouchMode(false);
18 return v;
19 case 2:
20 isThirdExpanded = isExpanded;
21 break;
22 }
23
24 v = super.getGroupView(groupPosition, isExpanded, convertView, parent);
25 v.setFocusable(false);
26 v.setFocusableInTouchMode(false);
27 return v;
28 }

Und hier überschreibe ich letzendlich die Methode getChildView(), da ja auch je nach dem ob beide Adressen gleich sind oder nicht auch eine Childiew weniger angezeigt wird
1@Override
2 public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, final ViewGroup parent) {
3 switch(groupPosition) {
4 case 0:
5 convertView = getLieferAdressEingabe(parent);
6 break;
7 case 1:
8 if(!isAdressSame()) {
9 convertView = getRechnungsAdressEingabe(parent);
10 break;
11 }
12 case 2:
13 convertView = getProfilVorteileView(parent);
14 break;
15 default:
16 convertView = new LinearLayout(parent.getContext());
17 }
18
19 convertView.setFocusable(false);
20 convertView.setFocusableInTouchMode(false);
21 return convertView;
22 }

Und hier zeichne ich die View neu wenn die CheckBox verändert worden ist
1public void setAdressSame(boolean isSame) {
2 isAdressSame = isSame;
3 notifyDataSetChanged();
4 }

Wie gesagt, es gibt nur Probleme in der View für die Lieferadresse, mit der Rechnungsadresse klappt alles einwandfrei (soweit sie natürlich auch eingeblendet ist). Lieferadresse und Rechnungsadresse sind bis auf die CheckBox komplett gleich (beide greifen auf das selbe XML-Layout zurück) und damit haben auch beide RadioButtons zum wählen der Anrede (Herr, Frau, Firma). Diese können überall wunderbar angewählt werden, nur bei der View mit der Lieferadresse wo die CheckBox integriert ist funktioniert es irgendwann nicht mehr. Nachdem man dann ein wenig in den anderen Views des ExpandableListViews umher geklickt hat, funktioniert es dann eigentlich auch immer =/

Komplexes Problem und ich find den Fehler einfach nicht, hoffe ihr wisst da mehr als ich :'(

Antworten
Felix
  • Forum-Beiträge: 259

18.01.2012, 14:05:07 via Website

Tach!

Ich poste euch mal ein bisschen Quellcode dazu und hoffe das mir hierbei jemand helfen kann, ich weiß nämlich nicht mehr woran dasl iegen könnte. =/

Ein bisschen? Nun, das ist relativ viel Code. Er hilft nur nicht viel, um das Problem selbst nachvollziehen zu können, ohne noch eine Menge anderes Zeug hinzuzufügen, um die Sache zum Laufen zu bekommen. Zudem ist viel vermutlich Unnötiges dabei, beispielsweise Formatierungsangaben für diverse Elemente. Ich schlage vor, du erstellst ein neues Projekt und bringst in dieses nur das Allernötigste, um das Problem nachstellen zu können. Das hilft gerade bei solchen Fehlern, die sich nicht lokalisieren lassen wollen. Zumindest hilft es, sich auf das Wesentliche konzentrieren zu können. Und beim Um-Rat-Fragen haben es die potentiellen Helfer auch einfacher, sich einerseits zurecht und andererseits die mögliche Ursache zu finden.

… bis auf ein paar kleinere Fehler, nämlich das die oberste View in welcher die CheckBox ist (die für die Lieferadresse) manchmal einige Klicks nicht entgegen nimmt. Allerdings nur bei CheckBoxen und RadioButtons, bei Textfeldern funktioniert alles immer tadellos.

Ich vermute mal, da verschwinden vorher ein paar Click- oder Touch-Ereignisse in anderen Views als dir lieb ist. Um dem auf die Spur zu kommen, könntest du für alle dem Namen nach infrage kommenden Ereignisse deiner beteiligen Views einen rudimentären Handler erstellen, Breakpoints in sie hineinsetzen und schauen, was in welcher Reihenfolge aufgerufen wird. Für solch einen Testfall hilft dir auch das oben vorgeschlagene Erstellen eines Minimal-Test-Projekts.


Felix.

Antworten
Philip M.
  • Forum-Beiträge: 90

18.01.2012, 15:35:47 via Website

Okay ich habe den Fehler ein wenig eingegrenzt.
Die Klicks die ich auf die CheckBox ausübe, scheinen sich ab einem bestimmten Moment (welchen ich noch nicht gefunden habe) zu sammeln. Denn sobald ich zum Beispiel 10 mal drauf klicke passiert nicht, aber wenn ich dann aufmal auf eine andere View klicke, wird erst mal 10 mal die onClick Methode auf die CheckBox ausgeübt.

Ich habe allen Views eine Textausgabe mit Log.d(String, String) gegeben um zu sehen wann wo welcher klick ankommt und dies ist nun das Verhalten welches ich beobachten konnte. Hat hierzu vielleicht noch jemand eine Idee? Ich weiß einfach nicht wo der Fehler liegen könnte =/

Ich poste einfach mal meinen neuen Versuch welcher ein bisschen weniger Quellcode enthält.

[code]
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initializeExpandableListView();
}

private List<HashMap<String, String>> createGroupList(Object array[], String key) {
if(array == null || key == null)
return null;

ArrayList<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
for( int i = 0 ; i < array.length ; ++i ) {
HashMap<String, String> m = new HashMap<String, String>();
m.put( key, array[i].toString() );
result.add(m);
}
return (List<HashMap<String, String>>)result;
}


private List<ArrayList<HashMap<String, String>>> createChildList(String array[], String key) {
if(array == null || key == null)
return null;

ArrayList<ArrayList<HashMap<String, String>>> result = new ArrayList<ArrayList<HashMap<String, String>>>();
for( int i = 0 ; i < array.length ; ++i ) {

ArrayList<HashMap<String, String>> secList = new ArrayList<HashMap<String, String>>();
HashMap<String, String> child = new HashMap<String, String>();
child.put( key, array[i] );
secList.add(child);
result.add(secList);
}
return result;
}



private void initializeExpandableListView() {
ExpandableListView exListView = (ExpandableListView) findViewById(R.id.exListView);
exListView.setAdapter(new SimpleExpandableListAdapter(this,
createGroupList(new String[] {"Test1", "Test2", "Test3"}, "adressDatenAngabe"),
android.R.layout.simple_expandable_list_item_1,
new String[] { "adressDatenAngabe"},
new int[] { android.R.id.text1 },
createChildList(new String[] { "Child1", "Child2", "Child3"}, "profil"),
android.R.layout.expandable_list_content,
new String[] {"profil"},
new int[] { }) {

private boolean isSame = false;
private LinearLayout checkBoxLayout = null;
private CheckBox sameAdressCheckBox = null;

private boolean isFirstExpanded = false;
private boolean isSecondExpanded = false;
private boolean isThirdExpanded = false;

private LinearLayout view1 = null;
private LinearLayout view2 = null;
private LinearLayout view3 = null;

@Override
public int getGroupCount() {
if(isSame)
return super.getGroupCount() - 1;
else
return super.getGroupCount();
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

View v = null;

switch (groupPosition) {
case 0:
isFirstExpanded = isExpanded;
v = super.getGroupView(groupPosition, isExpanded, convertView, parent);
break;
case 1:
if(isSame) {
isThirdExpanded = isExpanded;
v = super.getGroupView(groupPosition+1, isThirdExpanded, convertView, parent);
} else {
isSecondExpanded = isExpanded;
v = super.getGroupView(groupPosition, isSecondExpanded, convertView, parent);
}
return v;
case 2:
isThirdExpanded = isExpanded;
v = super.getGroupView(groupPosition, isExpanded, convertView, parent);
break;
}
return v;
}


@Override
public View getChildView(int groupPosition,
int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {


switch(groupPosition) {
case 0:
if(view1 == null) {
view1 = new LinearLayout(parent.getContext());
((LinearLayout)view1).setOrientation(LinearLayout.VERTICAL);
TextView tv1 = new TextView(parent.getContext());
tv1.setText("TextView1");
((LinearLayout)view1).addView(tv1);
((LinearLayout)view1).addView(getSameAdressCheckbox(parent));
}
convertView = view1;
break;
case 1:
if(!isSame) {
if(view2 == null) {
view2 = new LinearLayout(parent.getContext());
TextView tv2 = new TextView(parent.getContext());
tv2.setText("TextView2");
CheckBox cb2 = new CheckBox(parent.getContext());
cb2.setText("Testtext");
((LinearLayout)view2).addView(cb2);
((LinearLayout)view2).addView(tv2);
convertView = view2;

break;
}

case 2:
if(view3 == null) {
view3 = new LinearLayout(parent.getContext());
TextView tv3 = new TextView(parent.getContext());
tv3.setText("TextView3");
((LinearLayout)view3).addView(tv3);
}
convertView = view3;
break;
}
return convertView;
}


private LinearLayout getSameAdressCheckbox(ViewGroup parent) {
if(sameAdressCheckBox == null) {
checkBoxLayout = new LinearLayout(parent.getContext(), null);
sameAdressCheckBox = new CheckBox(parent.getContext());
sameAdressCheckBox.setText("Liefer- und Rechnungsadresse sind identisch");
sameAdressCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sameAdressCheckBox.setChecked(isChecked);
isSame = isChecked;
notifyDataSetChanged();
}
});
checkBoxLayout.addView(sameAdressCheckBox);
}
return checkBoxLayout;
}

});
}
[/code]

Hier ist die XML in welcher das Layout eingebettet ist.

1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <ExpandableListView
8 android:id="@+id/exListView"
9 android:layout_width="match_parent"
10 android:layout_height="wrap_content" >
11 </ExpandableListView>
12
13</LinearLayout>


Die ganzen onClick Methoden zur Überprüfung habe ich aufgrund der besseren Lesbarbeit heraus genommen. Bei dem geposteten Quellcode handelt es sich um den kompletten Adapter für den ExpandableListView.

— geändert am 19.01.2012, 09:16:40

Antworten
Felix
  • Forum-Beiträge: 259

18.01.2012, 16:41:10 via Website

Tach!

Ich poste einfach mal meinen neuen Versuch welcher ein bisschen weniger Quellcode enthält.

Es geht weniger um die Menge sondern mehr um die Nützlichkeit des geposteten Codes für das Nachvollziehen. Die gegebenen Stücke kann ich jedenfalls nicht zu einem lauffähigen Projekt ergänzen und damit auch das Fehlerbild nicht rekonstruieren.


Felix.

Antworten
Philip M.
  • Forum-Beiträge: 90

18.01.2012, 16:51:25 via Website

?
Klar geht das!
Mache ein Projekt mit einer View, welche nur einen ExpandableListView enthält, mach auf den ExpandableListView einfach setAdapter, füge einen SimpleExpandableListAdapter hinzu und überschreibe die Methoden die ich hier alle gepostet habe.
Und diese Methoden sind allein dafür verantwortlich das ich ein einzelnes Element ein- sowie ausblenden kann.

Ich weiß nicht was du mit zu viel bzw zu wenig meinst.

Antworten
Felix
  • Forum-Beiträge: 259

18.01.2012, 19:38:50 via Website

Tach!

Ich weiß nicht was du mit zu viel bzw zu wenig meinst.

Unter zu viel verstehe ich, wenn ich Code gezeigt bekomme, der weder zum Problem beiträgt noch notwendig ist, um mittels einfachem Kopieren ein lauffähiges Projekt zu erstellen. Unter zu wenig verstehe ich, wenn ich noch deutlich mehr Aufwand treiben muss, als mittels einfachem Kopieren ein lauffähiges Projekt zu erstellen.

Beim Überschreiben des SimpleExpandableListAdapter bremst mich in meinem Tatendrang, dass ich einen Konstruktor überschreiben muss, der 9, 10 oder 11 Parameter übergeben bekommen möchte. Den muss ich dann auch noch beim setAdapter() aufrufen und mir erarbeiten, wo ich denn für diese 9 bis 11 Parameter passende Werte herbekomme. Ich wünsche mir, dass du mir, im Gegenzug dass ich mich mit deinem Problem beschäftige, all diese Arbeiten abnimmst. Bei komplexen Problemen, so wie dieses eins zu sein scheint, fände ich es supertoll, ein fertiges, gezipptes, minimalmöglichstes (Eclipse-)Projekt laden zu können. Ich gebe mich jedoch schon zufrieden, wenn ich mir alles notwendige aus (d)einem Posting kopieren kann – und das obwohl die hiesige Forumssoftware einem das Kopieren nicht gerade einfach macht.


Felix.

Antworten
Philip M.
  • Forum-Beiträge: 90

19.01.2012, 09:18:04 via Website

Okay, jetzt weiß ich auch was du meinst :-)

Ich habe meinen Quellcode dementsprechend oben ergänzt und es sollte so nun auch compilierbar sein. :)
Und 'tschuldige für die Unannehmlichkeiten und danke das du dich mit meinem Problem beschäftigst. :)

Anbei vielleicht hilft es ja zur Fehlersuche bei, ich hatte gestern noch irgendwo gelesen das man mit dem ViewHolder Pattern das Problem lösen könnte. Allerdings habe ich hierzu positive sowie negative Rezesionen zu gelesen. Versuch jetzt seit gestern Abend mich in dieses Pattern rein zu arbeiten und habe hier auch schon einige kleinere Erfolge gehabt, so dass ich es heute für mein Problem umzuschreiben versuchen werde. Vielleicht hast du ja Erfahrung in diesem Pattern und weißt ob es mein Problem lösen könnte oder nicht? Ich werde es ansonsten weiter versuchen es für mich anzupassen.

— geändert am 19.01.2012, 09:22:24

Antworten
Felix
  • Forum-Beiträge: 259

19.01.2012, 18:30:14 via Website

Tach!

Ich habe eine gute und eine schlechte Nachricht. Die gute ist: ich konnte den Fehler nachstellen. Die schlecht ist: die Ursache hat sich mir auch nicht offenbart.

Die Klicks die ich auf die CheckBox ausübe, scheinen sich ab einem bestimmten Moment (welchen ich noch nicht gefunden habe) zu sammeln. Denn sobald ich zum Beispiel 10 mal drauf klicke passiert nicht, aber wenn ich dann aufmal auf eine andere View klicke, wird erst mal 10 mal die onClick Methode auf die CheckBox ausgeübt.

Alles geht gut, solange die Gruppe an zweiter Position eingeklappt bleibt. Sobald du diese aufklappst, kommen die Click-Ereignisse (erst einmal) nicht mehr beim Handler an. Dabei ist es egal, ob es Test2 oder 3 ist, Hauptsache es ist die Position nach dem Test1.

Vielleicht solltest du darüber nachdenken, was anderes als die ExpandableListView zu verwenden, wenn die sich so affig hat. Du gebrauchst sie ja auch nicht ganz bestimmungsgemäß.


Felix.

Antworten
Philip M.
  • Forum-Beiträge: 90

20.01.2012, 09:57:57 via Website

Da hast du wohl recht, bei dem ganzen zusammen biegen und brechen brauch man sich nicht wundern das mal solch ein Fehler entsteht.
Nichts desto trotz habe ich es jetzt nach 2 1/2 Tagen endlich geschafft und der Fehler tritt bei mir nun nicht mehr auf. Gelöst habe ich das ganze in der Tat mit dem ViewHolder Pattern, wobei ich bisher nicht genaz verstanden habe warum es auf diese Art und Weise funktioniert. Der Nachteil des ganzen ist hier nun natürlich das ich die Daten mir selbst merken muss für den fall das die View neu gezeichnet wird und damit die alte überschrieben wird. =/

Ich poste einfach mal meine Lösung als Quellcode in der Hoffnung das es vielleicht anderen leuten weiter hilft und bedanke mich trotzdem ganz herzlich für deine Mühe Felix. (:

Anbei möchte ich mich auch gleich dafür entschuldigen das der Code-Tag dieses Forums nur sehr spärlich funktioniert und damit auf meine Unschuld hinweisen das die Formatierung des Quellcodes für 'n Arsch ist (:

[code]
public class ExpandableListViewTestActivity extends Activity {

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


private List<HashMap<String, String>> createGroupList(Object array[], String key) {
if(array == null || key == null)
return null;

ArrayList<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
for( int i = 0 ; i < array.length ; ++i ) {
HashMap<String, String> m = new HashMap<String, String>();
m.put( key, array[i].toString() );
result.add(m);
}
return (List<HashMap<String, String>>)result;
}


private List<ArrayList<HashMap<String, String>>> createChildList(String array[], String key) {
if(array == null || key == null)
return null;

ArrayList<ArrayList<HashMap<String, String>>> result = new ArrayList<ArrayList<HashMap<String, String>>>();
for( int i = 0 ; i < array.length ; ++i ) {

ArrayList<HashMap<String, String>> secList = new ArrayList<HashMap<String, String>>();
HashMap<String, String> child = new HashMap<String, String>();
child.put( key, array[i] );
secList.add(child);
result.add(secList);
}
return result;
}

private void initializeExpandableListView() {
ExpandableListView exListView = (ExpandableListView) findViewById(R.id.exListView);

exListView.setAdapter(new SimpleExpandableListAdapter(this,
createGroupList(new String[] {"Test1", "Test2", "Test3"}, "adressDatenAngabe"),
android.R.layout.simple_expandable_list_item_1,
new String[] { "adressDatenAngabe"},
new int[] { android.R.id.text1 },
createChildList(new String[] { "Child1", "Child2", "Child3"}, "profil"),
android.R.layout.expandable_list_content,
new String[] {"profil"},
new int[] { }) {
// ================================ ADAPTER =====================================

private Map<Integer, Model> Data = new HashMap<Integer, Model>();
private boolean areSame = false;



/* (non-Javadoc)
* @see android.widget.SimpleExpandableListAdapter#getGroupCount()
*/
@Override
public int getGroupCount() {
if(areSame)
return super.getGroupCount()-1;
else
return super.getGroupCount();
}

/* (non-Javadoc)
* @see android.widget.SimpleExpandableListAdapter#getGroupView(int, boolean, android.view.View, android.view.ViewGroup)
*/
@Override
public View getGroupView(int groupPosition,
boolean isExpanded, View convertView,
ViewGroup parent) {
View v = convertView;

switch (groupPosition) {
case 1:
if(areSame) {
v = super.getGroupView(groupPosition+1, isExpanded, convertView, parent);
} else {
v = super.getGroupView(groupPosition, isExpanded, convertView, parent);
}
v.setFocusable(false);
v.setFocusableInTouchMode(false);
return v;
}

v = super.getGroupView(groupPosition, isExpanded, convertView, parent);
return v;
}


private int getItemViewType(View position) {
ViewHolder holder = (ViewHolder) position.getTag();
return holder.viewType;
}

@Override
public View getChildView(int groupPosition,
int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {

int viewType = 0;

if(convertView != null)
viewType = this.getItemViewType(convertView);

if(areSame && groupPosition == 1)
groupPosition += 1;

if(!Data.containsKey(groupPosition))
Data.put(groupPosition, new Model());

ViewHolder holder;

View v = convertView;

switch(groupPosition) {

case 0:
if (v == null || viewType != 1) {
v = new LinearLayout(parent.getContext());
CheckBox cb = new CheckBox(parent.getContext());
TextView tv = new TextView(parent.getContext());
TextView tv2 = new TextView(parent.getContext());


holder = new ViewHolder();
holder.cb = cb;
holder.cb.setTag(groupPosition);
holder.tv = tv;
holder.tv2 = tv2;
holder.viewType = 1;

((LinearLayout)v).addView(holder.cb);
((LinearLayout)v).addView(holder.tv);
((LinearLayout)v).addView(holder.tv2);
v.setTag(holder);
} else {
holder = (ViewHolder)v.getTag();
holder.cb.setTag(groupPosition);
}

holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int position = (Integer) buttonView.getTag();
Model model = Data.get(position);

buttonView.setChecked(isChecked);
model.setSelected(isChecked);
areSame = isChecked;
notifyDataSetChanged();
}
});

holder.cb.setText("Hallo Child 1");
holder.cb.setTextColor(0xFFFFFFFF);
holder.cb.setChecked(Data.get(groupPosition).isSelected());
holder.tv.setText("Test Child 1");
holder.tv.setTextColor(0xFFFF00CC);
holder.tv2.setTextColor(0xFFFF00CC);
holder.tv2.setText(" Ich bin oben!");
break;
case 1:
if(!areSame) {
if (v == null || viewType != 0) {
v = new LinearLayout(parent.getContext());
CheckBox cb = new CheckBox(parent.getContext());
TextView tv = new TextView(parent.getContext());



holder = new ViewHolder();
holder.cb = cb;
holder.cb.setTag(groupPosition);
holder.tv = tv;
holder.cb.setTag(groupPosition);
holder.viewType = 0;

((LinearLayout)v).addView(holder.cb);
((LinearLayout)v).addView(holder.tv);
v.setTag(holder);
} else {
holder = (ViewHolder)v.getTag();
holder.cb.setTag(groupPosition);
}

holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int position = (Integer) buttonView.getTag();
Model model = Data.get(position);

buttonView.setChecked(isChecked);
model.setSelected(isChecked);

}
});

holder.cb.setText("Hallo Child 2");
holder.cb.setTextColor(0xFFFFFFFF);
holder.cb.setChecked(Data.get(groupPosition).isSelected());
holder.tv.setText("Test Child 2");
holder.tv.setTextColor(0xFFFF00CC);

break;
}
case 2:
if (v == null || viewType != 0) {
v = new LinearLayout(parent.getContext());
CheckBox cb = new CheckBox(parent.getContext());
TextView tv = new TextView(parent.getContext());



holder = new ViewHolder();
holder.cb = cb;
holder.cb.setTag(groupPosition);
holder.tv = tv;
holder.cb.setTag(groupPosition);
holder.viewType = 0;

((LinearLayout)v).addView(holder.cb);
((LinearLayout)v).addView(holder.tv);
v.setTag(holder);
} else {
holder = (ViewHolder)v.getTag();
holder.cb.setTag(groupPosition);
}

holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int position = (Integer) buttonView.getTag();
Model model = Data.get(position);

buttonView.setChecked(isChecked);
model.setSelected(isChecked);


}
});



holder.cb.setText("Hallo Child 3");
holder.cb.setTextColor(0xFFFFFFFF);
holder.cb.setChecked(Data.get(groupPosition).isSelected());
holder.tv.setText("Test Child 3");
holder.tv.setTextColor(0xFFFF00CC);

break;
default:
if (v == null || viewType != 0) {
v = new LinearLayout(parent.getContext());
CheckBox cb = new CheckBox(parent.getContext());
TextView tv = new TextView(parent.getContext());

((LinearLayout)v).addView(cb);
((LinearLayout)v).addView(tv);



holder = new ViewHolder();
holder.viewType = 0;
holder.cb = cb;
holder.tv = tv;
v.setTag(holder);
} else {
holder = (ViewHolder)v.getTag();
}

holder.cb.setText("Default");
holder.cb.setTextColor(0xFFFFFFFF);
holder.tv.setText("Default");
holder.tv.setTextColor(0xFFFF00CC);
}

return v;
}

});
// =============================== ADAPTER END ====================================
}

public static class Model {

private boolean selected;

public Model() {
selected = false;
}

public boolean isSelected() {
return selected;
}

public void setSelected(boolean selected) {
this.selected = selected;
}

}

public static class ViewHolder {
protected CheckBox cb;
protected TextView tv;
protected TextView tv2;

protected int viewType;
}
}
[/code]

Antworten
Felix
  • Forum-Beiträge: 259

20.01.2012, 15:10:56 via Website

Tach!

Nichts desto trotz habe ich es jetzt nach 2 1/2 Tagen endlich geschafft und der Fehler tritt bei mir nun nicht mehr auf. Gelöst habe ich das ganze in der Tat mit dem ViewHolder Pattern, wobei ich bisher nicht genaz verstanden habe warum es auf diese Art und Weise funktioniert.

Das ViewHolder-Pattern ist nicht die Lösung gewesen. Selbiges erleichtert dir nur den Zugriff auf die CheckBox und die TextView-Elemente. Ich hab das mal so umgeschrieben, dass ich die ViewHolder-Klasse gelöscht habe und die Zugriffe, die darüber gingen, auf die Elemente direkt gelegt habe. Das heißt, dazu habe ich sie mir mit getChildAt() und zwei TypeCasts aus v/convertView geholt. Das ist natürlich umständlich und über das ViewHolder-Pattern wesentlich eleganter gelöst, trotzdem hat es auch so problemlos geklappt. Die entscheidende Änderung erfolgte also mit den Umbauten, die du außerdem noch vorgenommen hast.

Aber danke, dass ich nun ein neues Pattern kennengelernt habe, das wird mir selbst noch nützlich sein, schätze ich mal.

Anbei möchte ich mich auch gleich dafür entschuldigen das der Code-Tag dieses Forums nur sehr spärlich funktioniert und damit auf meine Unschuld hinweisen das die Formatierung des Quellcodes für 'n Arsch ist (:

Die Code-Auszeichnung (oder die BBCode-Erkennung) hat Probleme, wenn im Code sowas wie [i] vorkommt.

[code]for (int i = 0; i < x.length; i++)
x[i] = 42;[/code]

Siehste – kaputt. Das geht nur mit Trick 17 weg.

1for (int i = 0; i < x.length; i++)
2 x[­i] = 42;

Allerdings ist das jetzt nicht mehr ausführbar, weil das (normalerweise) unsichtbare U+00AD (Soft Hyphen) zwischen [ und i zwar vom Parser aber kaum vom Programmierer entdeckt wird. Schlimmer noch ist das Eclipse-Verhalten, das zeigt nun ein -i an, was aber kein Minus ist. (Und mit Zero-Width-Spaces wird die ganze Chose auch nicht besser.)


Felix.

Antworten