Android: SeperatedList (¿Cómo obtener el efecto de la libreta de direcciones?)

Hola a todos,

I have a ListView, which kontains a RadioGroup and a Button in each row. The ListView works well. Now i want to add a header to the ListView, to get the effect like the address book. I fund a Java Class from the Internet, which looks like this:

package com.aiquan.android.wljs_ncre3_free;

import java.util.LinkedHashMap;
import java.util.Map;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;

public class SeparatedListAdapter extends BaseAdapter {

 public final Map<String, Adapter> sections = new LinkedHashMap<String, Adapter>();
 public final ArrayAdapter<String> headers;
 public final static int TYPE_SECTION_HEADER = 0;

 public SeparatedListAdapter(Context context) {
  headers = new ArrayAdapter<String>(context, R.layout.list_header);
 }

 public void addSection(String sectionHeader, Adapter sectionAdapter) {
  this.headers.add(sectionHeader);
  this.sections.put(sectionHeader, sectionAdapter);
 }

 public Object getItem(int position) {
  for (Object section : this.sections.keySet()) {
   Adapter adapter = sections.get(section);
   int size = adapter.getCount() + 1;

   // check if position inside this section
   if (position == 0)
    return section;
   if (position < size)
    return adapter.getItem(position - 1);

   // otherwise jump into next section
   position -= size;
  }
  return null;
 }

 public int getCount() {
  // total together all sections, plus one for each section header
  int total = 0;
  for (Adapter adapter : this.sections.values())
   total += adapter.getCount() + 1;
  return total;
 }

 public int getViewTypeCount() {
  // assume that headers count as one, then total all sections
  int total = 1;
  for (Adapter adapter : this.sections.values())
   total += adapter.getViewTypeCount();
  return total;
 }

 public int getItemViewType(int position) {
  int type = 1;
  for (Object section : this.sections.keySet()) {
   Adapter adapter = sections.get(section);
   int size = adapter.getCount() + 1;

   // check if position inside this section
   if (position == 0)
    return TYPE_SECTION_HEADER;
   if (position < size)
    return type + adapter.getItemViewType(position - 1);

   // otherwise jump into next section
   position -= size;
   type += adapter.getViewTypeCount();
  }
  return -1;
 }

 public boolean areAllItemsSelectable() {
  return false;
 }

 public boolean isEnabled(int position) {
  return (getItemViewType(position) != TYPE_SECTION_HEADER);
 }

// @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  int sectionnum = 0;
  for (Object section : this.sections.keySet()) {
   Adapter adapter = sections.get(section);
   int size = adapter.getCount() + 1;

   // check if position inside this section
   if (position == 0)
    return headers.getView(sectionnum, convertView, parent);
   if (position < size)
    return adapter.getView(position - 1, convertView, parent);

   // otherwise jump into next section
   position -= size;
   sectionnum++;
  }
  return null;
 }

    // @Override
 public long getItemId(int position) {
  return position;
 }
    }

I try to use this class (without any change) to solve my problem. But i got a very strange effect: the part with RadioGroup and Buttons are not displayed, but the part with Strings are displayed correctly! And i got no error messages from Eclipse. Here is my code:

   SeparatedListAdapter adapter = new SeparatedListAdapter(this); 

    adapter.addSection("Header 1", new ArrayAdapter<String>(this,  
            R.layout.list_item, new String[] { "First item", "Item two" })); 

    adapter.addSection("Header 2", new ExerciseAdapter(this,  
            R.layout.sc_for_exam, n_exercises));

    adapter.addSection("Header 3", new ArrayAdapter<String>(this,  
            R.layout.list_item, new String[] { "lala", "lolo" }));

   setListAdapter(adapter);

n_exercises ist an ArrayList, which contains the List Items(each list item contains a RadioGroup and a Button). ExerciseAdapter extends from ArrayAdapter.

Now i got this effect: texto alternativo

Does anybody know what is wrong and how i can solve this problem? Thank you very much!!

Here is the code of ExerciseAdapter. They are in the same class like the code above.

private class ExerciseAdapter extends ArrayAdapter<Exercise_SC> {

    public ExerciseAdapter(Context context, int textViewResourceId,
            ArrayList<Exercise_SC> exes) {
        super(context, textViewResourceId, exes);
    }

    public View getView(final int position, View convertView,
            ViewGroup parent) {
        View row = convertView;
        SC_ViewWrapper wrapper;
        RadioGroup rg;

        if (row == null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            if (ChooseMode_Act.modeInfo.equalsIgnoreCase("Training")) {
                row = vi.inflate(R.layout.sc_for_training, parent, false);
            } else {
                row = vi.inflate(R.layout.sc_for_exam, parent, false);
            }
            wrapper = new SC_ViewWrapper(row);
            row.setTag(wrapper);
            rg = wrapper.getRadioGroup();

            RadioGroup.OnCheckedChangeListener l = new RadioGroup.OnCheckedChangeListener() {
                // @Override
                public void onCheckedChanged(RadioGroup group, int checkedId) {
                    Integer myPosition = (Integer) group.getTag();
                    Exercise_SC eRow = getExerciseRow(myPosition);
                    eRow.setCheckedRB(checkedId);
                    switch (checkedId) {
                    case R.id.RB_A:
                        n_exercises.get(myPosition).setCustomerAnswer("A");
                        break;
                    case R.id.RB_B:
                        n_exercises.get(myPosition).setCustomerAnswer("B");
                        break;
                    case R.id.RB_C:
                        n_exercises.get(myPosition).setCustomerAnswer("C");
                        break;
                    case R.id.RB_D:
                        n_exercises.get(myPosition).setCustomerAnswer("D");
                        break;
                    default:
                        n_exercises.get(myPosition).setCustomerAnswer("");
                    }
                }
            };
            rg.setOnCheckedChangeListener(l);
        } else {
            wrapper = (SC_ViewWrapper) row.getTag();
            rg = wrapper.getRadioGroup();
        }
        Exercise_SC myExe = getExerciseRow(position);
        int size = ChooseMode_Act.size;
        wrapper.getTi().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
        wrapper.getTVExer().setText(myExe.getExerciseText());
        wrapper.getTVExer().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);

        wrapper.getA().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
        wrapper.getTVA().setText(myExe.getAnswerA());
        wrapper.getTVA().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);

        wrapper.getB().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
        wrapper.getTVB().setText(myExe.getAnswerB());
        wrapper.getTVB().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);

        wrapper.getC().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
        wrapper.getTVC().setText(myExe.getAnswerC());
        wrapper.getTVC().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);

        wrapper.getD().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
        wrapper.getTVD().setText(myExe.getAnswerD());
        wrapper.getTVD().setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
        wrapper.getImageView().setImageResource(myExe.getImageSrc());

        if (ChooseMode_Act.modeInfo.equalsIgnoreCase("Training")) {
            wrapper.getButton().setOnClickListener(new OnClickListener() {
                // @Override
                public void onClick(View v) {
                    Toast toast = Toast.makeText(
                            getApplicationContext(),
                            "题-"
                                    + (position + 1)
                                    + ": "
                                    + n_exercises.get(position)
                                            .getCorrectAnswer(),
                            Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
                    toast.show();
                }
            });
        }
        rg.setTag(new Integer(position));
        rg.check(myExe.getCheckedRB());
        return row;
    }
}

preguntado el 08 de enero de 11 a las 22:01

Dame mi MergeAdapter a shot, as it works on a similar principle: github.com/commonsguy/cwac-merge -

Thank you very much. I will study it!! -

2 Respuestas

IMO SeparatedListAdapter.getView(...) looks suspicious. Put logging on it (or debug) to study how it works and what it returns. Looks like it never returns a View desde ExerciseAdapter.

ACTUALIZACIÓN: on a second thought I realized it does call ExerciseAdapter para View. So probably focus on what ExerciseAdapter.getView(...) returns being called from the SeparatedListAdapter.getView(...) context. Also could you post the ExerciseAdapter code?

Respondido el 09 de enero de 11 a las 01:01

Thank you for the answer! I have added the code of the ExerciseAdapter. - TianDong

@TianDong: sorry, still have no strong idea. - Vit Khudenko

Prueba esto:

public int getViewTypeCount() {
    // assume that headers count as one, then total all sections
    //int total = 1;
    //int total = 0;
    int total = headers.getCount() + 1;
    for (Adapter adapter : this.sections.values())
        //total += adapter.getViewTypeCount();
        total += (adapter.getCount() + 10);
    return total;
}

Don't know why but it worked for me. I read a tip from some other question that getItemViewType() couldn't be greater than getViewTypeCount().

Respondido 27 Oct 12, 02:10

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.