Como usar o ArrayAdapter <myClass>

129
ArrayList<MyClass> myList = new ArrayList<MyClass>();

ListView listView = (ListView) findViewById(R.id.list);

ArrayAdapter<MyClass> adapter = new ArrayAdapter<MyClass>(this, R.layout.row,
    to, myList.);
listView.setAdapter(adapter);

Classe: MyClass

class MyClass {
    public String reason;
    public long long_val;
}

Criei row.xml em layouts, mas não sei como mostrar razão e long_val no ListView usando ArrayAdapter.

Sumit M Asok
fonte

Respostas:

155

Implemente um adaptador personalizado para sua classe:

public class MyClassAdapter extends ArrayAdapter<MyClass> {

    private static class ViewHolder {
        private TextView itemView;
    }

    public MyClassAdapter(Context context, int textViewResourceId, ArrayList<MyClass> items) {
        super(context, textViewResourceId, items);
    }

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

        if (convertView == null) {
            convertView = LayoutInflater.from(this.getContext())
            .inflate(R.layout.listview_association, parent, false);

            viewHolder = new ViewHolder();
            viewHolder.itemView = (TextView) convertView.findViewById(R.id.ItemView);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        MyClass item = getItem(position);
        if (item!= null) {
            // My layout has only one TextView
                // do whatever you want with your string and long
            viewHolder.itemView.setText(String.format("%s %d", item.reason, item.long_val));
        }

        return convertView;
    }
}

Para aqueles que não estão familiarizados com a estrutura do Android, isso é explicado em mais detalhes aqui: https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView .

Nikola Smiljanić
fonte
2
Desculpe, item MyClass = items.get (position) resolve o erro, descompacta as variáveis ​​por mim.
Sumit M Asok
1
Eu tenho campo de itens removidos a partir do código acima, porque ele pode facilmente levar a erros - por exemplo, se alguém mudar lista interna de itens usando adapter.clear () ou adapter.add (...)
prostynick
1
Estou correto ao supor que textViewResourceIdnão é usado acima?
Gerrytan
8
De onde veio o viewHolder?
Gerry
2
O que é R.layout.listview_association? Esse é o seu layout personalizado? Posso substituí-lo por android.R.layout.simple_list_item_1?
Donard
76

Você pode simplesmente adicionar um toString()método ao MyClass, por http://developer.android.com/reference/android/widget/ArrayAdapter.html :

No entanto, o TextView é referenciado, ele será preenchido com o toString () de cada objeto na matriz. Você pode adicionar listas ou matrizes de objetos personalizados. Substitua o método toString () dos seus objetos para determinar qual texto será exibido para o item na lista.

class MyClass {

 @Override
 public String toString() {
  return "Hello, world.";
 }
}

fonte
20
Embora a solução mais simples, esta (IMHO) não seja uma ideia muito boa. Três razões: Se você precisar de localização, precisará refatorar. Isso funciona apenas se você tiver 1 adaptador, se você tiver 2 adaptadores diferentes MyClass, precisará refatorar. Finalmente, geralmente é uma má idéia vincular a lógica de apresentação aos seus modelos. Os modelos não devem estar cientes de como eles são apresentados ao usuário.
Fernandohur
2
para o endereço de alguns dos @fernandohur preocupações que você pode simplesmente criar uma classe vista dedicado para o ArrayAdapter ... então uma classe de modelo de tipo MyClassexigiria que você adicionar uma classe dedicada chamada MyClassViewque envolve o modelo subjacente (e fornece a toString( )implementação
wal
Esta resposta foi de 2011 e eu concordo com @fernandohur - existem maneiras melhores de lidar com isso agora.
Eu acho que essa é uma boa resposta porque, muitas vezes, cada classe tem um atributo que representa o nome do objeto.
Jhon Fredy Trujillo Ortega
Essa deve ser a resposta aceita. Substituir um adaptador apenas para vincular o nome impresso é uma codificação incorreta.
L.Grillo
22

Eu acho que essa é a melhor abordagem. O uso da classe ArrayAdapter genérica e estende seu próprio adaptador de objetos é tão simples como a seguir:

public abstract class GenericArrayAdapter<T> extends ArrayAdapter<T> {

  // Vars
  private LayoutInflater mInflater;

  public GenericArrayAdapter(Context context, ArrayList<T> objects) {
    super(context, 0, objects);
    init(context);
  }

  // Headers
  public abstract void drawText(TextView textView, T object);

  private void init(Context context) {
    this.mInflater = LayoutInflater.from(context);
  }

  @Override public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder vh;
    if (convertView == null) {
      convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
      vh = new ViewHolder(convertView);
      convertView.setTag(vh);
    } else {
      vh = (ViewHolder) convertView.getTag();
    }

    drawText(vh.textView, getItem(position));

    return convertView;
  }

  static class ViewHolder {

    TextView textView;

    private ViewHolder(View rootView) {
      textView = (TextView) rootView.findViewById(android.R.id.text1);
    }
  }
}

e aqui seu adaptador (exemplo):

public class SizeArrayAdapter extends GenericArrayAdapter<Size> {

  public SizeArrayAdapter(Context context, ArrayList<Size> objects) {
    super(context, objects);
  }

  @Override public void drawText(TextView textView, Size object) {
    textView.setText(object.getName());
  }

}

e finalmente, como inicializá-lo:

ArrayList<Size> sizes = getArguments().getParcelableArrayList(Constants.ARG_PRODUCT_SIZES);
SizeArrayAdapter sizeArrayAdapter = new SizeArrayAdapter(getActivity(), sizes);
listView.setAdapter(sizeArrayAdapter);

Eu criei um Gist com o ArrayAdapter personalizável por gravidade do layout do TextView:

https://gist.github.com/m3n0R/8822803

cesards
fonte
1
Gostei muito do seu código, mas demorei um pouco para descobrir por que ele estava travando com android.content.res.Resources $ NotFoundException: ID do recurso # 0x0. Você tem em sua chamada de adaptador genérica super (.., 0, ..), onde 0 é realmente um recurso de layout, que não existe, portanto deve ser alterado para outra coisa. Além disso, sua essência é 404
Ev0oD
No final, eu acabei mudando muito - layout do menu drop-down foi diferente do que o layout do item mostrado, o drawText só foi chamado no cabeçalho do girador, não sobre seus itens no clicado ..
Ev0oD
Isso deve ser válido como adaptador genérico. Você poderia resolver o problema?
Cesards 15/10/2015
Sim, eu fiz funcionar. Percebi que você fornecia uma solução para algo um pouco diferente do que eu queria, mas pude usar seu código como ponto de partida e fazer alterações da maneira que ele fez para mim o que eu queria. Obrigado por este pedaço de código.
Ev0oD
Isso deve ser fornecido por padrão.
Goddard
6

Subclasse ArrayAdapter e substitua o método getView () para retornar sua própria exibição que contém o conteúdo que você deseja exibir.

Klarth
fonte
5

Aqui está um exemplo rápido e sujo de como usar um ArrayAdapter se você não quiser se preocupar em estender a classe mãe:

class MyClass extends Activity {
    private ArrayAdapter<String> mAdapter = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mAdapter = new ArrayAdapter<String>(getApplicationContext(),
            android.R.layout.simple_dropdown_item_1line, android.R.id.text1);

        final ListView list = (ListView) findViewById(R.id.list);
        list.setAdapter(mAdapter);

        //Add Some Items in your list:
        for (int i = 1; i <= 10; i++) {
            mAdapter.add("Item " + i);
        }

        // And if you want selection feedback:
        list.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //Do whatever you want with the selected item
                Log.d(TAG, mAdapter.getItem(position) + " has been selected!");
            }
        });
    }
}
Francois Dermu
fonte