Android/Layouts predefinits pels adapters
Introducció
[modifica]Què és un Layout?
[modifica]Un Layout és una vista (View) que en pot contenir d'altres, que controla el comportament i la posició de les Views que conté. Els Layouts es poden declarar de dues formes:
- Declarar els elements UI en fitxers XML. Android proveeix un vocabulari XML que correspon a les classes i subclasses View.
- Crear elements Layout en temps d'execució. Una aplicació pot crear objectes View i ViewGroup (i manipular les seves propietats) a través de la programació Java.
Què és una ListView?
[modifica]Per a mostrar una llista en Android es fa ús d'una View anomenada ListView. És un contenidor de Views anònimes, disposades en forma de llistat, on cada fila és una View anònima.
- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple d'una declaració en XML d'una ListView dins d'un LinearLayout.
- Vegeu també: Android/Layouts predefinits pels adapters
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MyActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/llista" />
</LinearLayout>
El poblament del ListView significa generar tantes Views anònimes com files tingui la llista a visualitzar. El poblament pot ser estàtic o dinàmic.
El poblament estàtic és aquell que es realitza amb les dades estàtiques del XML, quan fem la construcció de l'arbre de views (procés d'inflat).
Per a realitzar un poblament dinàmic en una ListView cal:
- Font de dades. Es necessari un mecanisme homogeni que permeti alimentar les ListViews amb diferents fonts de dades.
- Generació de fila. Es necessari un mecanisme que es preocupi de construir una View anònima per cada fila, i que la pobli dinàmicament a partir de les dades de la font de dades.
Els Adapters resolen ambdues necessitats!
Què és un Adapter?
[modifica]Un Adapter actua com a pont entre un AdapterView (ex. ListView) i la capa de dades que hi ha per sota de la View. L'Adapter proveeix accés als items de dades. També és responsable de crear una View per a cada item en el conjunt de dades.
En la part esquerra del diagrama es pot observar com hi ha una font de dades (DataSource) la qual pot provenir d'una ArrayList o d'un Cursor que apunta a una base de dades.
A la dreta apareix una AdapterView (abstract class), una View en què els seus fills són determinats per l'Adapter que tingui assignat. Alguns exemples d'especificació d'un AdapterView són: ListView, GridView i Spinner.
Finalment es pot veure com l'Adapter fa de pont entre els dos elements del diagrama, construeix les Views filles per a l'AdapterView amb la informació de la font de dades.
Exemple ArrayAdapter:
- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple d'una declaració en java d'un ArrayAdapter.
- Vegeu també: Android/Layouts predefinits pels adapters
ArrayAdapter<String> adaptador =
new ArrayAdapter<String>(
this, // Context
android.R.layout.simple_list_item_1, // Layout predefinit
dadesEstatiques // Font de dades (Array)
);
L'Adapter pren la font de dades proporcionada i l'utilitza per a poblar la ListView usant el layout indicat. En aquest cas, un layout predefinit pel framework Android.
Constructor de l'ArrayAdapter
[modifica]ArrayAdapter(Context context, int resource)
ArrayAdapter(Context context, int resource, int textViewResourceId)
ArrayAdapter(Context context, int resource, T[] objects)
ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)
ArrayAdapter(Context context, int resource, List<T> objects)
ArrayAdapter(Context context, int resource, int textViewResourceId, List<T> objects)
- context: El context actual
- resource: La id d'un arxiu layout que conté un TextView que, quan es creïn les instàncies a les views, es poblarà amb la informació de la font de dades. Si no s'indica textViewResourceId l'identificador d'aquest TextView és text1
- textViewResourceId: La id del TextView que ha de ser poblat
- objects: Els objectes que s'han de representar a la ListView; és la font de dades
Constructor del SimpleCursorAdapter
[modifica]SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)
SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags)
- context: El context on la ListView associada amb el SimpleCursorAdapter està executant-se.
- layout: Identificador del recurs d'un fitxer layout el qual defineix les Views per aquest item de la llista. El fitxer hauria de contindre almenys les Views anomenades en "to".
- c: El cursor de la base de dades. Pot ser null si el cursor encara no està disponible.
- from: Una llista de noms de columna representant les dades unides a la UI.
- to: Les Views que s'haurien de mostrar en les columnes definides en el paràmetre "from". Haurien de ser totes TextViews.
- flags: Flags utilitzades per determinar el comportament de l'adapter. Veure FLAG_AUTO_REQUERY i FLAG_REGISTER_CONTENT_OBSERVER.
Layouts predefinits pels adapters
[modifica]El SDK d'Android proporciona una col·lecció de layouts fila predefinits (declaració XML) per a ser utilitzats en els Adapters. Aquests layouts corresponent a una fila de la llista.
Els podem trobar en: android.R.layout.xxxx
on xxxx és el nom del layout predefinit.
O en android.jar res\layout\
si accedim des de l'arbre de directoris del SDK.
Fitxer strings.xml
[modifica]Aquí s'ofereixen unes mostres que s'han fet servir en tots els exemples per poder comprovar ràpidament el funcionament dels adapters. Tens total llibertat per modificar aquest fitxer.
- Link al repositori: Pàgina principal d'Android
- Anotacions: Fitxer strings.xml que s'ha utlitzat per la realització d'aquestes proves.
- Vegeu també: Android/Layouts predefinits pels adapters
<resources>
<string-array name="contingut_llista_1">
<item>Anastasi Armengol</item>
<item>Biel Bosch</item>
<item>Celdoni Cardona</item>
<item>Damia Danes</item>
<item>Estanislau Estruch</item>
<item>Ferran Fortuny</item>
<item>Guifré Grau</item>
<item>Homer Hipolit</item>
<item>Isidre Ivern</item>
<item>Just Jonquera</item>
</string-array>
<string-array name="contingut_llista_2">
<item>anastasi_armengol@correu.cat</item>
<item>bbosch@correu.cat</item>
<item>cardona@correu.cat</item>
<item>damia1714@correu.cat</item>
<item>estanislauvng@correu.cat</item>
<item>ferryfortuny@correu.cat</item>
<item>ggrau@correu.cat</item>
<item>homerhipolit@correu.cat</item>
<item>ivern@correu.cat</item>
<item>justbcn@correu.cat</item>
</string-array>
</resources>
simple_list_item_1.xml
[modifica]Layout fila compost per un TextView.
ArrayAdapter
[modifica]Per a inflar la ListView s'utilitzarà l'Adapter predefinit ArrayAdapter. Aquest serà l'encarregat de generar les diferents files (Views) amb la font de dades corresponent (Array).
ExampleSimpleListItem1.java
[modifica]- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple ArrayAdapter.
- Vegeu també: Android/Layouts predefinits pels adapters
<source lang="java">
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class ExampleSimpleListItem1 extends Activity {
private ListView llistaContenidora;
private String[] dadesEstatiques;
private ArrayAdapter<String> adaptador;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_list_item_1);
carregaDades();
inicialitza();
}
// Carregar dades des d'un array XML
private void carregaDades() {
dadesEstatiques = getResources().getStringArray(R.array.contingut_llista_1);
}
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
// Crear un ArrayAdapter
adaptador =
new ArrayAdapter<String>(
this, // Context
android.R.layout.simple_list_item_1, // Layout predefinit
dadesEstatiques // Font de dades (Array)
);
// Assignar Adapter al ListView
llistaContenidora.setAdapter(adaptador);
}
}
Comentaris sobre el codi
[modifica]En aquest metode es carreguen les dades que s'han mostrat a la llista:
carregaDades();
Per fer-ho, cal accedir a les dades de tipus string desades com a recurs XML. Per defecte l'arxiu XML on s'ha definit aquest recurs és l'strings.xml:
dadesEstatiques = getResources().getStringArray(R.array.contingut_llista_1);
En aquest metode s'obté i es prepara la ListView per què s'adapti segons les necessitats:
inicialitza();
En primer lloc s'obté la ListView des de la layout:
llistaContenidora = (ListView) findViewById(R.id.llista);
I tot seguit s'enllaça la ListView obtinguda amb l'adapter:
llistaContenidora.setAdapter(adaptador);
simple_list_item_2.xml
[modifica]Layout fila compost per dos TextView, cada un representat per una mida i colors diferents.
En aquest tipus de layout amb dos TextView, l'ArrayAdapter no funciona correctament, ja que ell espera un layout amb un sol TextView. Per solucionar aquest problema existeixen dues possibles solucions:
- Crear un custom Adapter. Adapter personalitzat.
- Utilitzar un SimpleCursorAdapter.
Custom Adapter
[modifica]A partir de l'ArrayAdapter es crearà un Adapter personalitzat (Custom) que suporti un layout amb dues TextViews.
Caldrà fer un constructor nou i Override del mètode getView.
CustomAdapter.java
[modifica]- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple CustomAdapter.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class CustomAdapter extends ArrayAdapter {
private int layoutId;
private LayoutInflater inflater;
private List<Person> persons;
// Constructor: cridar a la classe pare (super) i guardar les dades necessàries (context, ArrayList<Person> i el id del layout)
public CustomAdapter(Context context, int resource, List<Person> persons) {
super(context, resource, persons);
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.persons = persons;
this.layoutId = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
// Si la row (View) no ha estat creada encara, s'infla a partir del layout predefinit
if (row == null) {
row = inflater.inflate(layoutId, parent, false);
}
// Obtenir TextViews continguts en el layout predefinit
TextView name = (TextView) row.findViewById(android.R.id.text1);
TextView email = (TextView) row.findViewById(android.R.id.text2);
// Assignar els valors corresponents a la font de dades
name.setText(this.persons.get(position).getName());
email.setText(this.persons.get(position).getEmail());
return row;
}
}
Classe Person.java:
package es.example.victor.myapplication;
/**
* Created by victor on 18/09/16.
*/
public class Person {
String nom;
String correu;
public Person(String nom, String correu) {
this.nom = nom;
this.correu = correu;
}
public String getName() {
return nom;
}
public String getEmail() {
return correu;
}
}
Comentaris sobre el codi
[modifica]Si es el primer cop i no hi ha cap fila creada, s'infla la view amb el layout predefinit
if (row == null) {
row = inflater.inflate(layoutId, parent, false);
}
Pobem els dos TextView amb les dades guardades a la llista de persones
name.setText(this.persons.get(position).getName());
email.setText(this.persons.get(position).getEmail());
ExempleSimpleListItem2.java
[modifica]- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple utilitzacio CustomAdapter
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class ExempleSimpleListItem2 extends Activity {
private ListView llistaContenidora;
private CustomAdapter adaptador;
private ArrayList<Person> dadesEstatiques = new ArrayList<Person>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_list_item_2);
carregaDades();
inicialitza();
}
// Carregar dades des de 2 arrays(name, email) del XML
private void carregaDades() {
String[] dadesName = getResources().getStringArray(R.array.contingut_llista_1);
String[] dadesEmail = getResources().getStringArray(R.array.contingut_llista_2);
// Introduir els objectes Persona(name, email) dins de l'ArrayList<Person>
for (int i = 0; i < dadesName.length; i++) {
dadesEstatiques.add(new Person(dadesName[i], dadesEmail[i]));
}
}
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
// Crear el CustomAdapter
adaptador =
new CustomAdapter(
this, // Context
android.R.layout.simple_list_item_2, // Layout predefinit
dadesEstatiques // Font de dades (ArrayList<Person>)
);
// Assignar Adapter al ListView
llistaContenidora.setAdapter(adaptador);
}
}
Comentaris sobre el codi
[modifica]Per emmagatzemar les dades del XML es farà ús d'un ArrayList de Persona. Aquesta classe contindrà els atributs nom i e-mail.
for (int i = 0; i < dadesName.length; i++) {
dadesEstatiques.add(new Person(dadesName[i], dadesEmail[i]));
}
SimpleCursorAdapter
[modifica]Per a la utilització d'un SimpleCursorAdapter, s'haurà d'emprar un cursor, la qual cosa obliga a fer ús d'una base de dades.
Amb l'ArrayAdapter si no dèiem res cada String de la font de dades poblava el TextView del layout anomenat text1. Ara però cal fer el mapeig de les columnes del Cursor a les Views del layout de fila de la ListView manualment.
AndroidManifest.xml
[modifica]En el següent exemple s'utilitzarà la base de dades dels contactes que incorpora Android, per tant caldrà sol·licitar el permís READ_CONTACTS en el AndroidManifest.xml:
<uses-permission
android:name="android.permission.READ_CONTACTS" />
ExampleSimpleListItem2SimpleCursorAdapter.java
[modifica]Fent ús de la mateixa base de dades dels contactes del dispositiu Android, facilitarà la representació de l'exemple:
- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple SimpleCursorAdapter.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class ExampleSimpleListItem2SimpleCursorAdapter extends Activity {
private ListView llistaContenidora;
private SimpleCursorAdapter adaptador;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_list_item_2);
inicialitza();
}
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
String[] projection = new String[]{
Data._ID,
Data.DISPLAY_NAME,
Phone.TYPE,
Phone.NUMBER};
Cursor cursor = getContentResolver().query(
Data.CONTENT_URI,
projection,
Data.MIMETYPE + "= '" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Phone.NUMBER + " IS NOT NULL",
null,
null);
String[] columns = new String[]{Data.DISPLAY_NAME, Phone.NUMBER};
// Crear un SimpleCursorAdapter
adaptador =
new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2,
cursor,
columns,
new int[] {android.R.id.text1, android.R.id.text2},
1);
// Assignar Adapter al ListView
llistaContenidora.setAdapter(adaptador);
}
Comentaris sobre el codi
[modifica]Creació d'un array d'Strings que especifica la llista de columnes que retornarà la consulta de la base de dades.
String[] projection = new String[]{
Data._ID,
Data.DISPLAY_NAME,
Phone.TYPE,
Phone.NUMBER};
Creació d'un Cursor a partir de la consulta a la base de dades.
Cursor cursor = getContentResolver().query(
Data.CONTENT_URI,
projection,
Data.MIMETYPE + "= '" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Phone.NUMBER + " IS NOT NULL",
null,
null);
L'equivalència a una consulta SQL seria la següent:
Data.CONTENT_URI
la font de les dades (FROM)projection
la llista de les columnes a retornar (SELECT)Data.MIMETYPE + [...] + "IS NOT NULL"
filtre que declara quines columnes seran retornades (WHERE)null
reemplaça qualsevol interrogant (?) en la selecció anterior (complementari al WHERE)null
ordena les files retornades (ORDER BY)
Llista de les columnes que utilitzarà l'adapter per a la creació de les files.
String[] columns = new String[]{Data.DISPLAY_NAME, Phone.NUMBER};
Per a la creació del SimpleCursorAdapter es necessitarà el Context, el layout predefinit, un Cursor de la BD, columnes que utilitzarà l'adapter, els layouts enllaçats als TextViews i un flag que determina el comportament de l'adapter.
adaptador = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2,
cursor,
columns,
new int[] {android.R.id.text1, android.R.id.text2},
1);
simple_list_item_single_choice.xml
[modifica]Layout fila compost per un TextView i un RadioButton.
ArrayAdapter
[modifica]Per a inflar la ListView s'utilitzarà l'Adapter predefinit ArrayAdapter. Aquest serà l'encarregat de generar les diferents files (Views) amb la font de dades corresponent (Array).
ExempleSimpleListItemSingleChoice.java
[modifica]- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple ArrayAdapter.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class ExempleSimpleListItemSingleChoice extends Activity {
private ListView llistaContenidora;
private String[] dadesEstatiques;
private ArrayAdapter<String> adaptador;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_list_item_single_choice);
carregaDades();
inicialitza();
}
// Carregar dades des d'un array XML
private void carregaDades() {
dadesEstatiques = getResources().getStringArray(R.array.contingut_llista_1);
}
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
// Crear un ArrayAdapter
adaptador = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_single_choice,
dadesEstatiques);
// Tria el tipus de selecció que es vol aplicar a la llista, en aquest cas només es permet una tria
llistaContenidora.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Assignar Adapter al ListView
llistaContenidora.setAdapter(adaptador);
}
}
Comentaris sobre el codi
[modifica]Defineix quin tipus de selecció s'aplica a la llista. En aquest cas es podrà escollir únicament una opció.
llistaContenidora.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Recuperació i marcació a través de codi
[modifica]Per recuperar la posició marcada es fa servir aquest metode sobre la ListView:
int posicio = llistaContenidora.getCheckedItemPosition();
De la mateixa manera per marcar una de les posicions només se li ha d'especificar quina d'elles.
int posicio = 4;
llistaContenidora.setItemChecked(posicio, true);
A continuació, es mostra una altra forma de recuperar i marcar a través de codi fen servir un custom adapter. Al fer servir un custom adapter alliberem responsabilitats de l'activity i es delega a l'adapter la gestió del marcatge i de la recuperació de les dades.
- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple per recuperar informació a partir d'un CustomAdapter.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
nom_pref = getString(R.string.preference_file_key);
prefs = getSharedPreferences(nom_pref, Context.MODE_PRIVATE);
editor = prefs.edit();
// Creem el custom adapter
adaptador = new SimpleListCustomAdapter(
this,
android.R.layout.simple_list_item_single_choice,
arrayListDadesEstatiques,
nom_pref);
llistaContenidora.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
llistaContenidora.setAdapter(adaptador);
// Es captura l'event de polsació d'un item de la llista
llistaContenidora.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Es guarda la posició polsada (la marcada) a SharedPreferences
editor.putInt("marcada", position);
editor.commit();
}
});
}
I aquest és el custom adapter:
- Link al repositori: Pàgina principal d'Android
- Anotacions: Custom adapter utilitzat.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class SimpleListCustomAdapter extends ArrayAdapter {
private int layoutId;
private LayoutInflater inflater;
private List<String> llista;
SharedPreferences prefs;
public SimpleListCustomAdapter(Context context, int resource, List<String> llista, String nom_pref) {
super(context, resource, llista);
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.layoutId = resource;
this.llista = llista;
this.prefs = context.getSharedPreferences(nom_pref, Context.MODE_PRIVATE);
}
@Override
public View getView(final int position, View row, ViewGroup parent) {
// Si la row (View) no ha estat creada encara, s'infla a partir del layout predefinit
if (row == null) {
row = inflater.inflate(layoutId, parent, false);
}
// Obtenir TextViews continguts en el layout predefinit
final CheckedTextView checkbox = (CheckedTextView) row.findViewById(android.R.id.text1);
// Assignar els valors corresponents a la font de dades
checkbox.setText(this.llista.get(position));
// Comprovar si hi ha dades guardades al Shared Preferences
int marcada = prefs.getInt("marcada", -1);
// Comprovar si la posició guardada és la marcada
if (marcada == position) {
((ListView)parent).setItemChecked(position,true);
} else {
((ListView)parent).setItemChecked(position,false);
}
return row;
}
}
simple_list_item_multiple_choice.xml
[modifica]Layout fila compost per un TextView i un CheckBox.
ArrayAdapter
[modifica]Per a inflar la ListView s'utilitzarà l'Adapter predefinit ArrayAdapter. Aquest serà l'encarregat de generar les diferents files (Views) amb la font de dades corresponent (Array).
ExampleSimpleListItemMultipleChoice.java
[modifica]- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple d'un ArrayAdapter utilitzant una llista list_item_Multiple_Choice.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class ExampleSimpleListItemMultipleChoice extends Activity {
private ListView llistaContenidora;
private String[] dadesEstatiques;
private ArrayAdapter<String> adaptador;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_list_item_multiple_choice);
carregaDades();
inicialitza();
}
// Carregar dades des d'un array XML
private void carregaDades() {
dadesEstatiques = getResources().getStringArray(R.array.contingut_llista_1);
}
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
// Crear un Adapter
adaptador =
new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_multiple_choice,
dadesEstatiques
);
// Tria el tipus de selecció que es vol aplicar a la llista, en aquest cas permet més d'una tria
llistaContenidora.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
// Assignar Adapter al ListView
llistaContenidora.setAdapter(adaptador);
}
}
Comentaris sobre el codi
[modifica]Defineix quin tipus de selecció s'aplica a la llista. En aquest cas es podrà escollir més d'una opció.
llistaContenidora.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Recuperació i marcació a través de codi
[modifica]Per recuperar quines posicions estan marcades es fa servir aquest mètode sobre la ListView.
SparseBooleanArray posicio = llistaContenidora.getCheckedItemPositions();
Retornarà un Array de booleans amb les posicions marcades (true) i no marcades (false).
Exemple per recórrer totes les posicions i saber si han estat marcades o no.
for (int i = 0; i < adaptador.getCount(); i++){
Log.i("checked?", String.valueOf(positions.get(i)));
}
De la mateixa manera per marcar una de les posicions només se li ha d'especificar quina d'elles.
int posicio = 4;
llistaContenidora.setItemChecked(posicio, true);
A continuació, es mostra una altra forma de recuperar i marcar a través de codi fen servir un custom adapter. Al fer servir un custom adapter alliberem responsabilitats de l'activity i es delega al adapter la gestió del marcatge i de la recuperació de les dades.
- Link al repositori: Pàgina principal d'Android
- Anotacions: Exemple per recuperar informació a partir d'un CustomAdapter y utilitzant el listener per capturar el OnItemClick d'un element de la llista.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
private void inicialitza() {
llistaContenidora = (ListView) findViewById(R.id.llista);
nom_pref = getString(R.string.preference_file_key);
prefs = getSharedPreferences(nom_pref, Context.MODE_PRIVATE);
editor = prefs.edit();
// Crear un Adapter
adaptador =
new SimpleListCustomAdapter(
this,
android.R.layout.simple_list_item_multiple_choice,
arrayListDadesEstatiques,
nom_pref
);
// Assignar el tipus de mètode d'entrada
llistaContenidora.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
// Assignar Adapter al ListView
llistaContenidora.setAdapter(adaptador);
// Es captura l'event de polsació d'un item de la llista
llistaContenidora.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView <?> adapterView, View view, int position, long id) {
// Recuperar quin valor te la posició polsada
boolean marcada = prefs.getBoolean(String.valueOf(position), false);
if (marcada) editor.remove(String.valueOf(position)); // if true: vol dir que estava marcada, per tant s'esborrarà
else editor.putBoolean(String.valueOf(position), true); // else: vol dir que estava desmarcada, per tant es guardarà com a true
editor.commit();
}
});
}
I aquest és el custom adapter:
- Link al repositori: Pàgina principal d'Android
- Anotacions: CustomAdapter utilitzat en l'exemple anterior.
- Vegeu també: Android/Layouts predefinits pels adapters
//Provat en les versions 4.1.2 i 4.2.2 d'Android
public class SimpleListCustomAdapter extends ArrayAdapter {
private int layoutId;
private LayoutInflater inflater;
private List<String> llista;
SharedPreferences prefs;
public SimpleListCustomAdapter(Context context, int resource, List<String> llista, String nom_pref) {
super(context, resource, llista);
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.layoutId = resource;
this.llista = llista;
this.prefs = context.getSharedPreferences(nom_pref, Context.MODE_PRIVATE);
}
@Override
public View getView(final int position, View row, ViewGroup parent) {
// Si la row (View) no ha estat creada encara, s'infla a partir del layout predefinit
if (row == null) {
row = inflater.inflate(layoutId, parent, false);
}
// Obtenir TextViews continguts en el layout predefinit
final CheckedTextView checkbox = (CheckedTextView) row.findViewById(android.R.id.text1);
// Assignar els valors corresponents a la font de dades
checkbox.setText(this.llista.get(position));
// Comprovar si hi han dades guardades al Shared Preferences
boolean marcada = prefs.getBoolean(String.valueOf(position), false);
// Comprovar si la posició guardada està marcada
if (marcada) {
((ListView)parent).setItemChecked(position,true);
} else {
((ListView)parent).setItemChecked(position,false);
}
return row;
}
}