Aquest article segueix del principal Android en aquesta wiki.
ListView és un widget obsolet.Referències:
Com veurem ara a l'hora d'implementar-ho, la ListView resulta una mica més complicada del què ens esperaríem. Això es deu a la particularitat dels dispositius mòbils de la seva escassa RAM. No podem, doncs, implementar una llista amb gran quantitat d'entrades que poden contenir pesants elements multimèdia com fotos d'alta resolució, i que es carreguin totes a la RAM directament. Ens cal uns tipus de Views que carreguin només les dades que s'estan visualitzant, i que generin nous ítems només quan l'usuari faci el scroll.
Com podem veure a la imatge, el sistema farà un reciclat dels ítems que ha generat prèviament i que ja no estan visibles, estalviant RAM de forma global.
View intenta seguir un paradigma Model - Vista - Controlador.ArrayList) connectat directament a la ListView.Activity) o en una classe derivada de la ListView.Adapter. Aquest és l'element que coneix la View i el nostre Model i que ha de saber com reciclar els ítems per a l'estalvi de RAM.
Per a cada element (item) de la ListView es necessita un layout personalitzat. El pots crear tu mateix, o simplement adoptar uns layouts prefabricats per als items. Al arxiu de recursos android.R.layout trobaràs alguns com per exemple android.R.layout.simple_list_item_1 que et pot estalviar feina per als casos més habituals.
Fixeu-vos en què:
'adapter es pot crear com una classe derivada, o bé un objecte particularitzat. En aquest cas és la 2a opció (objecte particularitzat «inline»).adapter.getView es realitza el reciclatge: si ens ve un objecte null, l'inicialitzem amb el LayoutInflater. Si no és null, el reciclem sobreescrivint i modificant les dades.class MainActivity : AppCompatActivity() { // Model: ArrayList de Record (intents=puntuació, nom) class Record(var intents: Int, var nom: String) var records: ArrayList<Record> = ArrayList<Record>() // ArrayAdapter serà l'intermediari amb la ListView lateinit var adapter: ArrayAdapter<Record> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } // Afegim alguns exemples records.add(Record(33, "Manolo")) records.add(Record(12, "Pepe")) records.add(Record(42, "Laura")) // Inicialitzem l'ArrayAdapter amb el layout pertinent adapter = object : ArrayAdapter<Record>(this,R.layout.list_item,records) { override fun getView(pos: Int, convertView: View?, container: ViewGroup): View { // getView ens construeix el layout i hi "pinta" els valors de l'element en la posició pos var convertView = convertView if (convertView == null) { // inicialitzem l'element la View amb el seu layout convertView = getLayoutInflater().inflate(R.layout.list_item, container, false) } // pintem imatge val bitmap = BitmapFactory.decodeStream( assets.open("ieti_logo.png") ) convertView.findViewById<ImageView>(R.id.imageView).setImageBitmap( bitmap ) // "Pintem" valors (quan es refresca) convertView.findViewById<TextView>(R.id.nom).text = getItem(pos)?.nom convertView.findViewById<TextView>(R.id.intents).text = getItem(pos)?.intents.toString() return convertView } } // busquem la ListView i li endollem l'ArrayAdapter val lv = findViewById<ListView>(R.id.recordsView) lv.setAdapter(adapter) } }
public class MainActivity extends AppCompatActivity { // Model: Record (intents=puntuació, nom) class Record { public int intents; public String nom; public Record(int _intents, String _nom ) { intents = _intents; nom = _nom; } } // Model = Taula de records: utilitzem ArrayList ArrayList<Record> records; // ArrayAdapter serà l'intermediari amb la ListView ArrayAdapter<Record> adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Inicialitzem model records = new ArrayList<Record>(); // Afegim alguns exemples records.add( new Record(33,"Manolo") ); records.add( new Record(12,"Pepe") ); records.add( new Record(42,"Laura") ); // Inicialitzem l'ArrayAdapter amb el layout pertinent adapter = new ArrayAdapter<Record>( this, R.layout.list_item, records ) { @Override public View getView(int pos, View convertView, ViewGroup container) { // getView ens construeix el layout i hi "pinta" els valors de l'element en la posició pos if( convertView==null ) { // inicialitzem l'element la View amb el seu layout convertView = getLayoutInflater().inflate(R.layout.list_item, container, false); } // "Pintem" valors (també quan es refresca) ((TextView) convertView.findViewById(R.id.nom)).setText(getItem(pos).nom); ((TextView) convertView.findViewById(R.id.intents)).setText(Integer.toString(getItem(pos).intents)); return convertView; } }; // busquem la ListView i li endollem el ArrayAdapter ListView lv = (ListView) findViewById(R.id.recordsView); lv.setAdapter(adapter); // botó per afegir entrades a la ListView Button b = (Button) findViewById(R.id.button); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { for (int i=0;i<3;i++) { records.add(new Record(100, "Anonymous")); } // notificar l'adapter dels canvis al model adapter.notifyDataSetChanged(); } }); } }
Implementa el codi d'exemple en un nou projecte anomenat «Listilla».
ActivityMain per l'exemple.package perquè concordi amb el teu projecte.activity_main.xml una ListView anomenada recordsView.list_item.xml que serà el placeholder per cada element de la llista. Pots crear-ho amb File -> New -> Layout Resource File
TextView amb IDs nom i intentsactivity_main.xml amb ID = button. Servirà per afegir ítems al ListView i comprovar el scroll del ListView.
Afegeix un botó Afegir rècord que ens ofereixi un Dialog per entrar nom i rècord.
Afegeix una imatge als elements de la llista (imatge fixa):
Solució 1:
ImageView amnb ID «imageView» al list_item.xml.app/src/main/assets al projecte.val bitmap = BitmapFactory.decodeStream( assets.open("ieti_logo.png") ) convertView.findViewById<ImageView>(R.id.imageView).setImageBitmap( bitmap )
Solució 2:
res -> drawable
Drawable.list_item.xml i afegir-hi una ImageView amb la imatge anterior.list_item perquè et quedi com la imatge suggerida adjunta.Record.
Afegeix un botó que ordeni la llista del model, i que refresqui la ListView.