Diferencia entre revisiones de «Spinner con Adaptadores»
Ir a la navegación
Ir a la búsqueda
(Página creada con «==Introdución== * Máis información en [https://developer.android.com/reference/android/widget/Spinner https://developer.android.com/reference/android/widget/Spinner] <…») |
|||
Línea 6: | Línea 6: | ||
*Xa vimos na unidade 2 como crear un [[Spinner]], pero o enlace dos datos co Spinner facíase a través dun atributo XML na definición do Spinner no Layout: '''android:entries'''. | *Xa vimos na unidade 2 como crear un [[Spinner]], pero o enlace dos datos co Spinner facíase a través dun atributo XML na definición do Spinner no Layout: '''android:entries'''. | ||
*Agora imos facer o mesmo pero usando un adaptador. | *Agora imos facer o mesmo pero usando un adaptador. | ||
− | *Colleremos os datos dende un array no código e | + | *Colleremos os datos dende un array no código e dende recursos gardados en /res/values de tipo array. |
+ | |||
+ | |||
+ | <br /> | ||
+ | ==Caso Base== | ||
+ | * O que imos aprender en primeiro lugar é o funcionamento básico do spinner. | ||
+ | :* Como cargar datos no spinner. | ||
+ | :* Como modificar visualmente o aspecto de cada elemento do spinner. | ||
+ | :* Como xestionar o evento de selección sobre un elemento do spinner. | ||
+ | :* Como acceder ao elemento seleccionado do spinner. | ||
+ | :* Como borrar, modificar ou engadir novos elementos ao spinner. | ||
+ | |||
+ | * Posteriormente veremos outras posibilidades que nos brinda este control | ||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | ===Preparando a Activity=== | ||
+ | |||
+ | * Imos crear unha Activity que visualmente teña este aspecto. | ||
+ | [[Imagen:PDM_spinner_base_1.jpg|300px|center]] | ||
+ | |||
+ | |||
+ | |||
+ | * Dentro do paquete '''Adaptadores''' crear unha nova 'Empty Activity' de nome: '''UD04_01_spinner_base''' de tipo Launcher. | ||
+ | : Modifica o arquivo '''AndroidManifiest.xml''' e engade unha label á activity como [http://wiki.cifprodolfoucha.es/index.php?title=PDM_Creando_proxecto_base xa vimos na creación do proxecto base]. | ||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | ===Código do Layoout=== | ||
+ | |||
+ | <syntaxhighlight lang="xml" enclose="div" highlight=""> | ||
+ | <?xml version="1.0" encoding="utf-8"?> | ||
+ | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ | xmlns:app="http://schemas.android.com/apk/res-auto" | ||
+ | xmlns:tools="http://schemas.android.com/tools" | ||
+ | android:layout_width="match_parent" | ||
+ | android:layout_height="match_parent" | ||
+ | tools:context=".adaptadores.UD04_01_Spinner_base"> | ||
+ | <Button | ||
+ | android:id="@+id/btnAlta" | ||
+ | android:layout_width="0dp" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:layout_margin="5dp" | ||
+ | android:text="Alta" | ||
+ | app:layout_constraintBottom_toBottomOf="parent" | ||
+ | app:layout_constraintEnd_toStartOf="@+id/btnBaixa" | ||
+ | app:layout_constraintHorizontal_bias="0.5" | ||
+ | app:layout_constraintStart_toStartOf="parent" /> | ||
+ | |||
+ | <Button | ||
+ | android:id="@+id/btnBaixa" | ||
+ | android:layout_width="0dp" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:layout_margin="5dp" | ||
+ | android:text="Baixa" | ||
+ | app:layout_constraintBottom_toBottomOf="parent" | ||
+ | app:layout_constraintEnd_toStartOf="@+id/btnModificar" | ||
+ | app:layout_constraintHorizontal_bias="0.5" | ||
+ | app:layout_constraintStart_toEndOf="@+id/btnAlta" /> | ||
+ | |||
+ | <Button | ||
+ | android:id="@+id/btnModificar" | ||
+ | android:layout_width="0dp" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:layout_margin="5dp" | ||
+ | android:text="Modificar" | ||
+ | app:layout_constraintBottom_toBottomOf="parent" | ||
+ | app:layout_constraintEnd_toEndOf="parent" | ||
+ | app:layout_constraintHorizontal_bias="0.5" | ||
+ | app:layout_constraintStart_toEndOf="@+id/btnBaixa" /> | ||
+ | |||
+ | <EditText | ||
+ | android:id="@+id/edtEditElemLista" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:layout_marginTop="8dp" | ||
+ | android:ems="10" | ||
+ | android:hint="Texto Elemento Lista" | ||
+ | android:inputType="textPersonName" | ||
+ | app:layout_constraintEnd_toEndOf="parent" | ||
+ | app:layout_constraintStart_toStartOf="parent" | ||
+ | app:layout_constraintTop_toTopOf="@+id/guideline" /> | ||
+ | |||
+ | <androidx.constraintlayout.widget.Guideline | ||
+ | android:id="@+id/guideline" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:orientation="horizontal" | ||
+ | app:layout_constraintGuide_percent="0.5" /> | ||
+ | |||
+ | <Spinner | ||
+ | android:id="@+id/spnSpinner" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:layout_marginStart="16dp" | ||
+ | android:layout_marginTop="8dp" | ||
+ | android:layout_marginEnd="16dp" | ||
+ | android:popupBackground="@android:color/holo_orange_light" | ||
+ | android:spinnerMode="dropdown" | ||
+ | app:layout_constraintEnd_toEndOf="parent" | ||
+ | app:layout_constraintStart_toStartOf="parent" | ||
+ | app:layout_constraintTop_toTopOf="parent" /> | ||
+ | </androidx.constraintlayout.widget.ConstraintLayout> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | |||
+ | ===Cargando datos=== | ||
+ | |||
+ | * O primeiro que temos que lograr facer é cargar os datos na lista. | ||
+ | : Isto o podemos facer de dúas formas: | ||
+ | :* Graficamente, a través da propiedade entreis do ListView. | ||
+ | :* Por código, facendo uso dun [https://developer.android.com/reference/android/widget/ArrayAdapter ArrayAdapter]. | ||
+ | |||
+ | <br /> | ||
+ | ====Cargando datos dende o Layout==== | ||
+ | |||
+ | |||
+ | * Xa vimos na unidade 2, [https://wiki.cifprodolfoucha.es/index.php?title=Spinner#Caso_pr.C3.A1ctico como cargar os datos dende o Layout] empregando un recurso string-array gardado nun arquivo de recurso en /res/values. | ||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | ====Cargando datos dende o código==== | ||
+ | |||
+ | * <u>Nota:</u> Quitamos a carga de datos se a temos na propiedade 'entries' do Spinner como vimos no punto anterior. | ||
+ | |||
+ | * Partimos do [https://wiki.cifprodolfoucha.es/index.php?title=Spinner#Caso_pr.C3.A1ctico exercicio de spinner feito anteriormente], no que está definido un array de strings, nun arquivo de /res/values: | ||
+ | <syntaxhighlight lang="xml" line enclose="div" highlight="" > | ||
+ | <?xml version="1.0" encoding="utf-8"?> | ||
+ | <resources> | ||
+ | |||
+ | <string-array name="array_datos_spinner"> | ||
+ | <item>Mercurio</item> | ||
+ | <item>Venus</item> | ||
+ | <item>Terra</item> | ||
+ | <item>Marte</item> | ||
+ | <item>Xúpiter</item> | ||
+ | <item>Saturno</item> | ||
+ | <item>Urano</item> | ||
+ | <item>Neptuno</item> | ||
+ | </string-array> | ||
+ | |||
+ | </resources> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | * Imos agora a ver o código necesario para cargar de datos ao spinner por programación. | ||
+ | : Para iso temos que facer uso dun Adapter, concretamente imos a empregar o [https://developer.android.com/reference/android/widget/ArrayAdapter ArrayAdapter] | ||
+ | : Lembrar que xa expliquei [https://wiki.cifprodolfoucha.es/index.php?title=Adaptadores o que era un adaptador]. | ||
+ | |||
+ | * Se nos fixamos nos contructores do adaptador: | ||
+ | [[Image:PDM_listview_base_5.jpg|300px|center]] | ||
+ | |||
+ | : Nos imos a empregar o terceiro constructor. | ||
+ | : Necesitimos indicarlle o layout que vai empregar para visualizar os elementos do spinner. Podemos empregar calquera sempre que teña a lo menos un TextView. | ||
+ | : Android proporciona xa uns predeterminados que podemos empregar, concretamente : '''android.R.layout.simple_spinner_item''' (podedes ver o deseño dende Android Studio premendo a tecla Control e premendo có rato sobre simple_spinner_item). | ||
+ | : Por outra banda necesitamos algún tipo de array que garde os datos. | ||
+ | |||
+ | :<u>Nota:</u> Indicar que o spinner ten dos views diferentes: | ||
+ | :* O view que visualiza o elemento que se atopa no spinner. | ||
+ | :* O view que aparece cando prememos no spinner e se despregan todos os elementos. Cada un deles está nun view. | ||
+ | |||
+ | |||
+ | ::<syntaxhighlight lang="java" enclose="div" highlight="5,6,8,11"> | ||
+ | public class UD04_01_Spinner_base extends AppCompatActivity { | ||
+ | |||
+ | private void cargarDatos(){ | ||
+ | |||
+ | String[]datos = getResources().getStringArray(R.array.array_datos_spinner); | ||
+ | ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,datos); | ||
+ | |||
+ | // adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // View que aparece cando prememos no spinner | ||
+ | |||
+ | Spinner spinner = findViewById(R.id.spnSpinner); | ||
+ | spinner.setAdapter(adapter); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected void onCreate(Bundle savedInstanceState) { | ||
+ | super.onCreate(savedInstanceState); | ||
+ | setContentView(R.layout.activity_u_d04_01__spinner_base); | ||
+ | |||
+ | cargarDatos(); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | : Liña 5: Como vemos obtemos os datos do string-array creado en /res/values no punto anterior. | ||
+ | : Liña 6: Creamos un adaptador empregando un layout do S.O. e mandamos os datos. | ||
+ | : Liña 8: Podemos cambiar o layout que se vai cargar ao despregar os elementos do spinner. | ||
+ | : Liña 11: Asociamos o adaptador ao spinner('''se non facemos isto non se cargará ningún dato'''). | ||
+ | |||
+ | |||
+ | * Podemos facer unha variante deste código e facer que os datos veñan dun ArrrayList: | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="3"> | ||
+ | private void cargarDatos(){ | ||
+ | |||
+ | ArrayList<String>datos = new ArrayList<>(Arrays.asList("Valor 1","Valor 2", "Valor 3")); | ||
+ | ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,datos); | ||
+ | |||
+ | // adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // View que aparece cando prememos no spinner | ||
+ | |||
+ | Spinner spinner = findViewById(R.id.spnSpinner); | ||
+ | spinner.setAdapter(adapter); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | ===Personalizando o deseño=== | ||
+ | |||
+ | * Antes vimos que no segundo parámetro temos que enviarlle o id do layout que vai representar cada un dos elementos da lista. | ||
+ | : Nos podemos crear o noso propio Layout. | ||
+ | : Por exemplo: | ||
+ | '''Layout: elemento_spinnerview''' | ||
+ | <syntaxhighlight lang="xml" enclose="div" highlight="20"> | ||
+ | ::<?xml version="1.0" encoding="utf-8"?> | ||
+ | <androidx.constraintlayout.widget.ConstraintLayout | ||
+ | xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ | xmlns:app="http://schemas.android.com/apk/res-auto" | ||
+ | xmlns:tools="http://schemas.android.com/tools" | ||
+ | android:layout_width="match_parent" | ||
+ | android:layout_height="match_parent"> | ||
+ | |||
+ | <TextView | ||
+ | android:id="@+id/textView" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:text="VALOR:" | ||
+ | android:textColor="@android:color/holo_purple" | ||
+ | android:textStyle="bold" | ||
+ | app:layout_constraintStart_toStartOf="parent" | ||
+ | app:layout_constraintTop_toTopOf="parent" /> | ||
+ | |||
+ | <TextView | ||
+ | android:id="@+id/txvElemSpinner" | ||
+ | android:layout_width="wrap_content" | ||
+ | android:layout_height="wrap_content" | ||
+ | android:layout_marginStart="8dp" | ||
+ | android:text="TextView" | ||
+ | app:layout_constraintStart_toEndOf="@+id/textView" | ||
+ | app:layout_constraintTop_toTopOf="parent" /> | ||
+ | </androidx.constraintlayout.widget.ConstraintLayout> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | : Agora imos decirlle ao adaptador que cargue este deseño, pero como dentro do mesmo hai dous TextView, temos que decirlle cal deles debe empregar para pasar o dato da fonte de datos ao view. | ||
+ | : Para iso empregamos outro dos contructores vistos anteriormente: | ||
+ | |||
+ | ::<syntaxhighlight lang="java" enclose="div" highlight="3"> | ||
+ | private void cargarDatos(){ | ||
+ | ArrayList<String>datos = new ArrayList<>(Arrays.asList("Valor 1","Valor 2", "Valor 3")); | ||
+ | ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.elemento_spinnerview,R.id.txvElemSpinner,datos); | ||
+ | |||
+ | Spinner spinner = findViewById(R.id.spnSpinner); | ||
+ | spinner.setAdapter(adapter); | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | : Liña 3: Fixarse en dúas cousas: Cargamos o layout deseñado por nos e enviamos como tecer parámetro o id do textview que se atopa dentro do layout. | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | ===Xestionando o evento Click sobre un elemento do spinner=== | ||
+ | * Para xestionar o evento Click debemos empregar a [https://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener?hl=en interface OnItemClickListener]. | ||
+ | |||
+ | : '''<u>NOTA IMPORTANTE:</u>''' Cando prememos nun elemento da lista este non queda seleccionado polo que non podemos empregar ningún método o interface que indique 'selected'. | ||
+ | |||
+ | <syntaxhighlight lang="java" enclose="div" highlight="5,6,16"> | ||
+ | private void xestionarEventos(){ | ||
+ | ListView lsvLista = findViewById(R.id.lsvLista); | ||
+ | lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
+ | @Override | ||
+ | public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { | ||
+ | Toast.makeText(getApplicationContext(), adapterView.getItemAtPosition(i).toString(),Toast.LENGTH_SHORT).show(); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected void onCreate(Bundle savedInstanceState) { | ||
+ | super.onCreate(savedInstanceState); | ||
+ | setContentView(R.layout.activity_u_d04_01__list_views_base); | ||
+ | |||
+ | cargarDatos(); | ||
+ | xestionarEventos(); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | : Liña 5: No método da interface onItemClick vai vir como parámetros: | ||
+ | :* O AdapterView, a través do cal | ||
+ | ::* Podemos acceder aos elementos que están cargados na lista. | ||
+ | ::* Podemos recuperar a referencia ao ArrayAdapter. | ||
+ | :* O View que foi premido (lembrar que se estamos a facer o exemplo, o view agora mesmo é o layout que fixemos con dous textview. | ||
+ | :* i é a posición do elemento seleccionado. | ||
+ | :* l é un identificador de fila (que non imos empregar). | ||
+ | |||
+ | O anterior é equivalente e isto se temos acceso aos array de datos: | ||
+ | |||
+ | <syntaxhighlight lang="java" enclose="div" highlight="3,17"> | ||
+ | public class UD04_01_ListViews_base extends AppCompatActivity { | ||
+ | |||
+ | private ArrayList<String>datos = new ArrayList<>(Arrays.asList("Valor 1","Valor 2", "Valor 3")); | ||
+ | |||
+ | private void cargarDatos(){ | ||
+ | |||
+ | ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.elemento_listview,R.id.txvElemLista,datos); | ||
+ | ListView listView = findViewById(R.id.lsvLista); | ||
+ | listView.setAdapter(adapter); | ||
+ | } | ||
+ | |||
+ | private void xestionarEventos(){ | ||
+ | ListView lsvLista = findViewById(R.id.lsvLista); | ||
+ | lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
+ | @Override | ||
+ | public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { | ||
+ | Toast.makeText(getApplicationContext(), datos.get(i).toString(),Toast.LENGTH_SHORT).show(); | ||
+ | } | ||
+ | }); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected void onCreate(Bundle savedInstanceState) { | ||
+ | super.onCreate(savedInstanceState); | ||
+ | setContentView(R.layout.activity_u_d04_01__list_views_base); | ||
+ | |||
+ | cargarDatos(); | ||
+ | xestionarEventos(); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | : Liña 3: Definimos o array a nivel de Activity para poder acceder a el dende calquera parte. | ||
+ | : Liña 17: Accedemos á posición do array. | ||
+ | |||
+ | : '''Curiosidade''': O parámetro 'view' nos permite acceder aos views que están dentro do layout que deseñamos. | ||
+ | : Por exemplo: | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="4,5"> | ||
+ | lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
+ | @Override | ||
+ | public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { | ||
+ | TextView tv = view.findViewById(R.id.txvElemLista); | ||
+ | tv.setTextColor(Color.RED); | ||
+ | Toast.makeText(getApplicationContext(), datos.get(i).toString(),Toast.LENGTH_SHORT).show(); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | ===Accedendo ao elemento seleccionado da lista=== | ||
+ | |||
+ | * O ListView non selecciona ningún elemento cando prememos nela, polo que non podemos empregar os métodos como: lista.getSelectedItem() | ||
+ | : Este tipo de chamadas devolverán sempre null no caso do ListView (si funcionan cun spinner). | ||
+ | |||
+ | : A única forma de saber cal é o elemento que premeu o usuario é gardando a posición nunha propiedade da Activity, no método onItemClick que vimos anteiormente. Veremos o seu uso na operación de baixa. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <br/> | ||
+ | ===Operacións sobre a lista=== | ||
+ | |||
+ | * Podemos facer alta, baixas e modificacións. | ||
+ | : Ditas operacións as podemos facer sobre o Array onde temos gardados os datos (sempre que estea definido a nivel de Activity ou de forma global) ou sobre o adaptador asociado á ListView. | ||
+ | : Imos velos das dúas formas: | ||
+ | |||
+ | <br/> | ||
+ | ====Operación de baixa==== | ||
+ | * Para dar de baixa un elemento necesitamos gardar a posición clickeada polo usuario. | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | =====Accedendo ao adaptador===== | ||
+ | : Supoñemos que non temos acceso ao array de datos (por estar definido localmente, por exemplo). | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="7-9"> | ||
+ | private void xestionarEventos(){ | ||
+ | findViewById(R.id.btnBaixa).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | if (posElemListaSelec==-1) return; | ||
+ | |||
+ | ArrayAdapter<String> adapter = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | String objeto = adapter.getItem(posElemListaSelec); | ||
+ | adapter.remove(objeto); | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | et.setText(""); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | ListView lsvLista = findViewById(R.id.lsvLista); | ||
+ | lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
+ | @Override | ||
+ | public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { | ||
+ | posElemListaSelec = i; | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | et.setText(datos.get(i)); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | : Liña 7: Ao non ter acceso ao array de datos, calquera operación a temos que facer a través do adaptador. Polo tanto necesitamos obter unha referencia ao adaptador da ListView. | ||
+ | : Liña 8: A través do adaptador podemos acceder ao elemento seleccionado pola posición que temos gardada previamente no método onItemClick. | ||
+ | : Liña 9: Eliminamos o elemento do adaptador. Automaticamente xa se refresca o ListView e desaparece o elemento. | ||
+ | |||
+ | <br /> | ||
+ | =====Accedendo ao array de datos===== | ||
+ | |||
+ | * Neste caso podemos acceder ao array de datos que está cargado no adaptador (polo telo definido a nivel de Activity, non localmente nun método). | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="6-8"> | ||
+ | findViewById(R.id.btnBaixa).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | if (posElemListaSelec==-1) return; | ||
+ | |||
+ | datos.remove(posElemListaSelec); | ||
+ | ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | adaptador.notifyDataSetChanged(); | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | et.setText(""); | ||
+ | } | ||
+ | }); | ||
+ | </syntaxhighlight> | ||
+ | : Liña 6: Eliminamos o elemento do array de datos. | ||
+ | : Liña 8-9: Necesitamos informar ao ListView que ten que recargar a lista, chamando ao método notifyDataSetChanged() do adaptador. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | ====Operación de Alta==== | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | =====Accedendo ao adaptador===== | ||
+ | : Supoñemos que non temos acceso ao array de datos (por estar definido localmente, por exemplo). | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="8,9"> | ||
+ | private void xestionarEventos(){ | ||
+ | findViewById(R.id.btnAlta).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | if (et.getText().toString().length()==0) return; | ||
+ | |||
+ | ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | adaptador.add(et.getText().toString()); | ||
+ | |||
+ | |||
+ | } | ||
+ | }); | ||
+ | |||
+ | findViewById(R.id.btnBaixa).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | if (posElemListaSelec==-1) return; | ||
+ | |||
+ | ArrayAdapter<String> adapter = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | String objeto = adapter.getItem(posElemListaSelec); | ||
+ | adapter.remove(objeto); | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | et.setText(""); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | ListView lsvLista = findViewById(R.id.lsvLista); | ||
+ | lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
+ | @Override | ||
+ | public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { | ||
+ | posElemListaSelec = i; | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | et.setText(datos.get(i)); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | : Liña 8: Ao non ter acceso ao array de datos, calquera operación a temos que facer a través do adaptador. Polo tanto necesitamos obter unha referencia ao adaptador da ListView. | ||
+ | : Liña 9: A través do adaptador podemos engadir o novo texto. | ||
+ | |||
+ | <br /> | ||
+ | =====Accedendo ao array de datos===== | ||
+ | |||
+ | * Neste caso podemos acceder ao array de datos que está cargado no adaptador (polo telo definido a nivel de Activity, non localmente nun método). | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="8,9"> | ||
+ | findViewById(R.id.btnAlta).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | if (et.getText().toString().length()==0) return; | ||
+ | |||
+ | ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | datos.add(et.getText().toString()); | ||
+ | adaptador.notifyDataSetChanged(); | ||
+ | |||
+ | et.setText(""); | ||
+ | } | ||
+ | }); | ||
+ | </syntaxhighlight> | ||
+ | : Liña 8: Añadimos o elemento ao array de datos. | ||
+ | : Liña 9: Necesitamos informar ao ListView que ten que recargar a lista, chamando ao método notifyDataSetChanged() do adaptador. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | <br /> | ||
+ | ====Operación de Modificar==== | ||
+ | |||
+ | * Necesitamos ter gardado nun atributo da clase, a posición do elemento seleccionado ao premer sobre a lista (como xa vimos nun exemplo anterior) | ||
+ | |||
+ | <br /> | ||
+ | =====Accedendo ao adaptador===== | ||
+ | : Supoñemos que non temos acceso ao array de datos (por estar definido localmente, por exemplo). | ||
+ | : O máis doado neste caso é borrar e dar de alta o novo elemento. | ||
+ | |||
+ | <syntaxhighlight lang="java" enclose="div" highlight="11,13"> | ||
+ | private void xestionarEventos(){ | ||
+ | findViewById(R.id.btnModificar).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | if (et.getText().toString().length()==0) return; | ||
+ | |||
+ | ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | |||
+ | String datoSel = (String)adaptador.getItem(posElemListaSelec); | ||
+ | adaptador.remove(datoSel); | ||
+ | String datoNuevo = et.getText().toString(); | ||
+ | adaptador.insert(datoNuevo,posElemListaSelec); | ||
+ | |||
+ | } | ||
+ | }); | ||
+ | |||
+ | ListView lsvLista = findViewById(R.id.lsvLista); | ||
+ | lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() { | ||
+ | @Override | ||
+ | public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { | ||
+ | posElemListaSelec = i; | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | et.setText(datos.get(i)); | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | : Liña 11: Borramos o elemento seleccionado. | ||
+ | : Liña 13: Engadimos o novo elemento. | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | =====Accedendo ao array de datos===== | ||
+ | |||
+ | * Neste caso podemos acceder ao array de datos que está cargado no adaptador (polo telo definido a nivel de Activity, non localmente nun método). | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight="6-8"> | ||
+ | findViewById(R.id.btnModificar).setOnClickListener(new View.OnClickListener() { | ||
+ | @Override | ||
+ | public void onClick(View view) { | ||
+ | EditText et = findViewById(R.id.edtEditElemLista); | ||
+ | if (et.getText().toString().length()==0) return; | ||
+ | |||
+ | ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter(); | ||
+ | datos.set(posElemListaSelec,et.getText().toString()); | ||
+ | adaptador.notifyDataSetChanged(); | ||
+ | } | ||
+ | }); | ||
+ | </syntaxhighlight> | ||
+ | : Liña 8: Modificamos o elemento do array de datos. | ||
+ | |||
+ | |||
+ | |||
+ | : <u>Curiosidade:</u> Podemos acceder ao view seleccionado mediante esta forma: | ||
+ | <syntaxhighlight lang="java" enclose="div" highlight=""> | ||
+ | View elemview = adaptador.getView(posElemListaSelec,View.inflate(getApplicationContext(),R.layout.elemento_listview,null),null); | ||
+ | ((TextView) elemview.findViewById(R.id.txvElemLista)).setText(et.getText().toString()); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | |||
+ | |||
+ | |||
+ | |||
Revisión del 21:06 10 nov 2020
Sumario
- 1 Introdución
- 2 Caso Base
- 3 Caso práctico 1
- 4 Caso práctico 2: Usando un array estático en Java
- 5 Caso práctico 3: Uso dun array dinámico
- 6 Caso práctico 4: Personalizando o deseño
Introdución
- Máis información en https://developer.android.com/reference/android/widget/Spinner
- Xa vimos na unidade 2 como crear un Spinner, pero o enlace dos datos co Spinner facíase a través dun atributo XML na definición do Spinner no Layout: android:entries.
- Agora imos facer o mesmo pero usando un adaptador.
- Colleremos os datos dende un array no código e dende recursos gardados en /res/values de tipo array.
Caso Base
- O que imos aprender en primeiro lugar é o funcionamento básico do spinner.
- Como cargar datos no spinner.
- Como modificar visualmente o aspecto de cada elemento do spinner.
- Como xestionar o evento de selección sobre un elemento do spinner.
- Como acceder ao elemento seleccionado do spinner.
- Como borrar, modificar ou engadir novos elementos ao spinner.
- Posteriormente veremos outras posibilidades que nos brinda este control
Preparando a Activity
- Imos crear unha Activity que visualmente teña este aspecto.
- Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_01_spinner_base de tipo Launcher.
- Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.
Código do Layoout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".adaptadores.UD04_01_Spinner_base">
<Button
android:id="@+id/btnAlta"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Alta"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btnBaixa"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btnBaixa"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Baixa"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/btnModificar"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/btnAlta" />
<Button
android:id="@+id/btnModificar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Modificar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/btnBaixa" />
<EditText
android:id="@+id/edtEditElemLista"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ems="10"
android:hint="Texto Elemento Lista"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<Spinner
android:id="@+id/spnSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:popupBackground="@android:color/holo_orange_light"
android:spinnerMode="dropdown"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Cargando datos
- O primeiro que temos que lograr facer é cargar os datos na lista.
- Isto o podemos facer de dúas formas:
- Graficamente, a través da propiedade entreis do ListView.
- Por código, facendo uso dun ArrayAdapter.
Cargando datos dende o Layout
- Xa vimos na unidade 2, como cargar os datos dende o Layout empregando un recurso string-array gardado nun arquivo de recurso en /res/values.
Cargando datos dende o código
- Nota: Quitamos a carga de datos se a temos na propiedade 'entries' do Spinner como vimos no punto anterior.
- Partimos do exercicio de spinner feito anteriormente, no que está definido un array de strings, nun arquivo de /res/values:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <string-array name="array_datos_spinner">
5 <item>Mercurio</item>
6 <item>Venus</item>
7 <item>Terra</item>
8 <item>Marte</item>
9 <item>Xúpiter</item>
10 <item>Saturno</item>
11 <item>Urano</item>
12 <item>Neptuno</item>
13 </string-array>
14
15 </resources>
- Imos agora a ver o código necesario para cargar de datos ao spinner por programación.
- Para iso temos que facer uso dun Adapter, concretamente imos a empregar o ArrayAdapter
- Lembrar que xa expliquei o que era un adaptador.
- Se nos fixamos nos contructores do adaptador:
- Nos imos a empregar o terceiro constructor.
- Necesitimos indicarlle o layout que vai empregar para visualizar os elementos do spinner. Podemos empregar calquera sempre que teña a lo menos un TextView.
- Android proporciona xa uns predeterminados que podemos empregar, concretamente : android.R.layout.simple_spinner_item (podedes ver o deseño dende Android Studio premendo a tecla Control e premendo có rato sobre simple_spinner_item).
- Por outra banda necesitamos algún tipo de array que garde os datos.
- Nota: Indicar que o spinner ten dos views diferentes:
- O view que visualiza o elemento que se atopa no spinner.
- O view que aparece cando prememos no spinner e se despregan todos os elementos. Cada un deles está nun view.
public class UD04_01_Spinner_base extends AppCompatActivity { private void cargarDatos(){ String[]datos = getResources().getStringArray(R.array.array_datos_spinner); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,datos); // adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // View que aparece cando prememos no spinner Spinner spinner = findViewById(R.id.spnSpinner); spinner.setAdapter(adapter); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_u_d04_01__spinner_base); cargarDatos(); } }
- Liña 5: Como vemos obtemos os datos do string-array creado en /res/values no punto anterior.
- Liña 6: Creamos un adaptador empregando un layout do S.O. e mandamos os datos.
- Liña 8: Podemos cambiar o layout que se vai cargar ao despregar os elementos do spinner.
- Liña 11: Asociamos o adaptador ao spinner(se non facemos isto non se cargará ningún dato).
- Podemos facer unha variante deste código e facer que os datos veñan dun ArrrayList:
private void cargarDatos(){
ArrayList<String>datos = new ArrayList<>(Arrays.asList("Valor 1","Valor 2", "Valor 3"));
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item,datos);
// adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // View que aparece cando prememos no spinner
Spinner spinner = findViewById(R.id.spnSpinner);
spinner.setAdapter(adapter);
}
Personalizando o deseño
- Antes vimos que no segundo parámetro temos que enviarlle o id do layout que vai representar cada un dos elementos da lista.
- Nos podemos crear o noso propio Layout.
- Por exemplo:
Layout: elemento_spinnerview
::<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="VALOR:"
android:textColor="@android:color/holo_purple"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/txvElemSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintStart_toEndOf="@+id/textView"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
- Agora imos decirlle ao adaptador que cargue este deseño, pero como dentro do mesmo hai dous TextView, temos que decirlle cal deles debe empregar para pasar o dato da fonte de datos ao view.
- Para iso empregamos outro dos contructores vistos anteriormente:
private void cargarDatos(){ ArrayList<String>datos = new ArrayList<>(Arrays.asList("Valor 1","Valor 2", "Valor 3")); ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.elemento_spinnerview,R.id.txvElemSpinner,datos); Spinner spinner = findViewById(R.id.spnSpinner); spinner.setAdapter(adapter); }
- Liña 3: Fixarse en dúas cousas: Cargamos o layout deseñado por nos e enviamos como tecer parámetro o id do textview que se atopa dentro do layout.
Xestionando o evento Click sobre un elemento do spinner
- Para xestionar o evento Click debemos empregar a interface OnItemClickListener.
- NOTA IMPORTANTE: Cando prememos nun elemento da lista este non queda seleccionado polo que non podemos empregar ningún método o interface que indique 'selected'.
private void xestionarEventos(){
ListView lsvLista = findViewById(R.id.lsvLista);
lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(getApplicationContext(), adapterView.getItemAtPosition(i).toString(),Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_u_d04_01__list_views_base);
cargarDatos();
xestionarEventos();
}
- Liña 5: No método da interface onItemClick vai vir como parámetros:
- O AdapterView, a través do cal
- Podemos acceder aos elementos que están cargados na lista.
- Podemos recuperar a referencia ao ArrayAdapter.
- O View que foi premido (lembrar que se estamos a facer o exemplo, o view agora mesmo é o layout que fixemos con dous textview.
- i é a posición do elemento seleccionado.
- l é un identificador de fila (que non imos empregar).
O anterior é equivalente e isto se temos acceso aos array de datos:
public class UD04_01_ListViews_base extends AppCompatActivity {
private ArrayList<String>datos = new ArrayList<>(Arrays.asList("Valor 1","Valor 2", "Valor 3"));
private void cargarDatos(){
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.elemento_listview,R.id.txvElemLista,datos);
ListView listView = findViewById(R.id.lsvLista);
listView.setAdapter(adapter);
}
private void xestionarEventos(){
ListView lsvLista = findViewById(R.id.lsvLista);
lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(getApplicationContext(), datos.get(i).toString(),Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_u_d04_01__list_views_base);
cargarDatos();
xestionarEventos();
}
}
- Liña 3: Definimos o array a nivel de Activity para poder acceder a el dende calquera parte.
- Liña 17: Accedemos á posición do array.
- Curiosidade: O parámetro 'view' nos permite acceder aos views que están dentro do layout que deseñamos.
- Por exemplo:
lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
TextView tv = view.findViewById(R.id.txvElemLista);
tv.setTextColor(Color.RED);
Toast.makeText(getApplicationContext(), datos.get(i).toString(),Toast.LENGTH_SHORT).show();
}
});
Accedendo ao elemento seleccionado da lista
- O ListView non selecciona ningún elemento cando prememos nela, polo que non podemos empregar os métodos como: lista.getSelectedItem()
- Este tipo de chamadas devolverán sempre null no caso do ListView (si funcionan cun spinner).
- A única forma de saber cal é o elemento que premeu o usuario é gardando a posición nunha propiedade da Activity, no método onItemClick que vimos anteiormente. Veremos o seu uso na operación de baixa.
Operacións sobre a lista
- Podemos facer alta, baixas e modificacións.
- Ditas operacións as podemos facer sobre o Array onde temos gardados os datos (sempre que estea definido a nivel de Activity ou de forma global) ou sobre o adaptador asociado á ListView.
- Imos velos das dúas formas:
Operación de baixa
- Para dar de baixa un elemento necesitamos gardar a posición clickeada polo usuario.
Accedendo ao adaptador
- Supoñemos que non temos acceso ao array de datos (por estar definido localmente, por exemplo).
private void xestionarEventos(){
findViewById(R.id.btnBaixa).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (posElemListaSelec==-1) return;
ArrayAdapter<String> adapter = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
String objeto = adapter.getItem(posElemListaSelec);
adapter.remove(objeto);
EditText et = findViewById(R.id.edtEditElemLista);
et.setText("");
}
});
ListView lsvLista = findViewById(R.id.lsvLista);
lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
posElemListaSelec = i;
EditText et = findViewById(R.id.edtEditElemLista);
et.setText(datos.get(i));
}
});
}
- Liña 7: Ao non ter acceso ao array de datos, calquera operación a temos que facer a través do adaptador. Polo tanto necesitamos obter unha referencia ao adaptador da ListView.
- Liña 8: A través do adaptador podemos acceder ao elemento seleccionado pola posición que temos gardada previamente no método onItemClick.
- Liña 9: Eliminamos o elemento do adaptador. Automaticamente xa se refresca o ListView e desaparece o elemento.
Accedendo ao array de datos
- Neste caso podemos acceder ao array de datos que está cargado no adaptador (polo telo definido a nivel de Activity, non localmente nun método).
findViewById(R.id.btnBaixa).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (posElemListaSelec==-1) return;
datos.remove(posElemListaSelec);
ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
adaptador.notifyDataSetChanged();
EditText et = findViewById(R.id.edtEditElemLista);
et.setText("");
}
});
- Liña 6: Eliminamos o elemento do array de datos.
- Liña 8-9: Necesitamos informar ao ListView que ten que recargar a lista, chamando ao método notifyDataSetChanged() do adaptador.
Operación de Alta
Accedendo ao adaptador
- Supoñemos que non temos acceso ao array de datos (por estar definido localmente, por exemplo).
private void xestionarEventos(){
findViewById(R.id.btnAlta).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText et = findViewById(R.id.edtEditElemLista);
if (et.getText().toString().length()==0) return;
ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
adaptador.add(et.getText().toString());
}
});
findViewById(R.id.btnBaixa).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (posElemListaSelec==-1) return;
ArrayAdapter<String> adapter = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
String objeto = adapter.getItem(posElemListaSelec);
adapter.remove(objeto);
EditText et = findViewById(R.id.edtEditElemLista);
et.setText("");
}
});
ListView lsvLista = findViewById(R.id.lsvLista);
lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
posElemListaSelec = i;
EditText et = findViewById(R.id.edtEditElemLista);
et.setText(datos.get(i));
}
});
}
- Liña 8: Ao non ter acceso ao array de datos, calquera operación a temos que facer a través do adaptador. Polo tanto necesitamos obter unha referencia ao adaptador da ListView.
- Liña 9: A través do adaptador podemos engadir o novo texto.
Accedendo ao array de datos
- Neste caso podemos acceder ao array de datos que está cargado no adaptador (polo telo definido a nivel de Activity, non localmente nun método).
findViewById(R.id.btnAlta).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText et = findViewById(R.id.edtEditElemLista);
if (et.getText().toString().length()==0) return;
ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
datos.add(et.getText().toString());
adaptador.notifyDataSetChanged();
et.setText("");
}
});
- Liña 8: Añadimos o elemento ao array de datos.
- Liña 9: Necesitamos informar ao ListView que ten que recargar a lista, chamando ao método notifyDataSetChanged() do adaptador.
Operación de Modificar
- Necesitamos ter gardado nun atributo da clase, a posición do elemento seleccionado ao premer sobre a lista (como xa vimos nun exemplo anterior)
Accedendo ao adaptador
- Supoñemos que non temos acceso ao array de datos (por estar definido localmente, por exemplo).
- O máis doado neste caso é borrar e dar de alta o novo elemento.
private void xestionarEventos(){
findViewById(R.id.btnModificar).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText et = findViewById(R.id.edtEditElemLista);
if (et.getText().toString().length()==0) return;
ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
String datoSel = (String)adaptador.getItem(posElemListaSelec);
adaptador.remove(datoSel);
String datoNuevo = et.getText().toString();
adaptador.insert(datoNuevo,posElemListaSelec);
}
});
ListView lsvLista = findViewById(R.id.lsvLista);
lsvLista.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
posElemListaSelec = i;
EditText et = findViewById(R.id.edtEditElemLista);
et.setText(datos.get(i));
}
});
}
- Liña 11: Borramos o elemento seleccionado.
- Liña 13: Engadimos o novo elemento.
Accedendo ao array de datos
- Neste caso podemos acceder ao array de datos que está cargado no adaptador (polo telo definido a nivel de Activity, non localmente nun método).
findViewById(R.id.btnModificar).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
EditText et = findViewById(R.id.edtEditElemLista);
if (et.getText().toString().length()==0) return;
ArrayAdapter adaptador = (ArrayAdapter)((ListView)findViewById(R.id.lsvLista)).getAdapter();
datos.set(posElemListaSelec,et.getText().toString());
adaptador.notifyDataSetChanged();
}
});
- Liña 8: Modificamos o elemento do array de datos.
- Curiosidade: Podemos acceder ao view seleccionado mediante esta forma:
View elemview = adaptador.getView(posElemListaSelec,View.inflate(getApplicationContext(),R.layout.elemento_listview,null),null);
((TextView) elemview.findViewById(R.id.txvElemLista)).setText(et.getText().toString());
- Se queremos cargar ditos recursos por programación:
- Deberemos facer uso dun obxecto da clase ArrayAdapter. Este obxecto serve coma ponte entre os datos e o spinner. A modificacións dos datos da lista sempre se fai no adaptador asociado á mesma e nunca sobre o spinner. Engadir, borrar, modificar, limpar,...todas esas operacións se teñen que facer sobre o adaptador.
- Deberemos de obter os datos para encher o spinner. Estes datos poden vir dun array gardado en /res/ e para referencialo teremos que facer uso do método getResources().
- Deberemos de establecer o aspecto (layout) que terá cada un dos 'views' que conforman cada elemento da lista (si, cada elemento da lista ten que ser un view :) )
- Deberemos establecer o aspecto (layout) de cada elemento do spinner cando prememos na lista e se despregan todos eles.
- Para crear un ArrayAdapter podemos seguir este código:
1 Spinner lista = findViewById(R.id.id_spinner);
2
3 ArrayAdapter<CharSequence>adaptador = ArrayAdapter.createFromResource(this,R.array.planetas_UD02_01_spinner,android.R.layout.simple_list_item_1);
4 adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
5 lista.setAdapter(adaptador);
- Na liña 3 creamos un ArrayAdapter facendo uso do método createFromResource. Dito método recibe como parámetros:
- O contexto
- Os datos do ArrayAdapter, que neste caso veñen dun recurso xa creado previamente noutro exercicio.
- O Layout que vai ter asociado cada view (elemento da lista, que dependendo do layout serán views como TextViews).
- Os layout que se poden empregar se poden consultar en http://wiki.cifprodolfoucha.es/index.php?title=Spinner#Caso_pr.C3.A1ctico
- O código fonte de cada layout se pode consultar en https://github.com/aosp-mirror/platform_frameworks_base/tree/master/core/res/res/layout
- Na liña 4, establecemos o layout que vai ter o spinner cando prememos sobre el e aparezan todos os elementos da lista. Podemos consultar o código fonte de dito layout.
- Na liña 5 asociamos o ArrayAdapter ao Spinner.
- Podemos facer o mesmo desta outra forma:
1 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.planetas_UD02_01_spinner));
- Para referenciar o array teríamos que facer uso da clase getResource() e obter o tipo correspondente (array).
- O ArrayAdapter está 'cheo' de métodos para engadir, borrar e modificar elementos da lista.
- Por exemplo:
- add(T object): Engade un elemento á lista de elementos.
- addAll(Collection<? extends T> collection): Engade unha colección.
- getCount(): Devolve o número de elementos da lista.
- getItem(int position): Devolve o elemento da lista en base a súa posición (empeza en 0)
- insert(T object, int index) : Engade un elemento na posición indicada.
- remove(T object): Elimina un elemento da lista.
- clear(): Borra todos os elementos da lista.
- Importante:
- Se o array que se lle envía ao adaptador coma fonte de datos non é dinámico (por exemplo, un Array de Strings) non poderemos facer ningunha operación sobre os datos.
- Calquera modificación que se faga sobre os elementos da lista facendo uso do adaptador, leva consigo a 'obriga' de informar ao view dos cambios para que os reflicta.
- Isto se consigo chamando a un destes dous métodos:
- Método setNotifyOnChange(boolean notifyOnChange), cun valor true no parámetro.
- Método notifyDataSetChanged.
- O segundo normalmente se chama cando hai algún cambio estrutural na lista (remove, add,...). En teoría chamarano o primeiro método automaticamente pero algunhas veces non funciona e é necesario chamalo explicitamente. Se debe chamar a un dos dous, non os dous.
- Por exemplo, o código anterior se podería cambiar por:
1 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item); 2 adapter.addAll(getResources().getStringArray(R.array.planetas_UD02_01_spinner)); 3 adapter.setNotifyOnChange(true);
- A xestión de eventos neste control inclúe a interface que controla cando un elemento da lista é premido. É a interface OnItemSelectedListener e se rexistra có método setOnItemSelectedListener(AdapterView.OnItemClickListener l) do Spinner.
- Ao facelo, deberá implementarse estes dous método:
1 @Override 2 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 3 4 } 5 6 @Override 7 public void onNothingSelected(AdapterView<?> parent) { 8 9 }
- O segundo método se chama cando non se selecciona ningún elemento e desaparece a lista.
- O primeiro cando se selecciona un elemento da lista.
- Leva como parámetros:
- O adaptador asociado á lista.
- O view que foi seleccionado (lembrar que cando se crea o adaptador se establece un layout para cada compoñente da lista)
- A posición do elemento seleccionado na lista (empeza en 0)
- Un identificador para a fila que foi seleccionada.
Caso práctico 1
- Partimos que xa temos creado o proxecto inicial como xa indicamos anteriormente.
- Se non o temos creado antes, crearemos un novo paquete de nome: Adaptadores como un subpaquete do teu paquete principal.
- Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_01_Spinners de tipo Launcher e sen compatibilidade.
- Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.
- Cada ítem do Spinner é tratado como unha View, neste caso de tipo TextView.
O XML do layout
- Observar como a vista Spinner non ten a entrada android:entries.
1 <?xml version="1.0" encoding="utf-8"?>
2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context=".Adaptadores.UD04_01_Spinners">
8
9 <Spinner
10 android:id="@+id/spnLista_UD02_02_spinner"
11 android:layout_width="0dp"
12 android:layout_height="wrap_content"
13 android:layout_marginEnd="8dp"
14 android:layout_marginStart="8dp"
15 android:layout_marginTop="8dp"
16 android:dropDownWidth="match_parent"
17 app:layout_constraintEnd_toEndOf="parent"
18 app:layout_constraintStart_toStartOf="parent"
19 app:layout_constraintTop_toTopOf="parent" />
20 </android.support.constraint.ConstraintLayout>
- Partimos do exercicio de spinner feito anteriormente, no que está definido un array de datos, nun arquivo de /res/values:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <string-array name="planetas_UD02_01_spinner">
5 <item>Mercurio</item>
6 <item>Venus</item>
7 <item>Terra</item>
8 <item>Marte</item>
9 <item>Xúpiter</item>
10 <item>Saturno</item>
11 <item>Urano</item>
12 <item>Neptuno</item>
13 </string-array>
14
15 </resources>
- O código da Activity:
1 package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.view.View;
6 import android.widget.AdapterView;
7 import android.widget.ArrayAdapter;
8 import android.widget.Spinner;
9 import android.widget.TextView;
10 import android.widget.Toast;
11
12 import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
13
14 public class UD04_01_Spinners extends Activity {
15
16 private void cargarLista() {
17
18 Spinner lista = findViewById(R.id.spnLista_UD02_02_spinner);
19
20 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1);
21 adapter.addAll(getResources().getStringArray(R.array.planetas_UD02_01_spinner));
22 lista.setAdapter(adapter);
23
24 lista.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
25 @Override
26 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
27 //String datoLista = (String)parent.getItemAtPosition(position); // Poderíamos obter o dato desta forma (fixarse no Cast)
28 String datoLista = ((TextView) view).getText().toString(); // ou desta outra forma
29 Toast.makeText(getApplicationContext(),"Elemento seleccionado:" + datoLista + " na posición "+ String.valueOf(position),Toast.LENGTH_LONG).show();
30 }
31
32 @Override
33 public void onNothingSelected(AdapterView<?> parent) {
34
35 }
36 });
37
38 }
39 @Override
40 protected void onCreate(Bundle savedInstanceState) {
41 super.onCreate(savedInstanceState);
42 setContentView(R.layout.activity_ud04_01__spinners);
43
44 cargarLista();
45
46 }
47 }
- Liñas 20-22: Usamos unha das formas vistas para crear o adaptador e asocialo ao spinner.
- Liña 24: Rexistramos a interface que xestiona o evento de selección dun elemento da lista.
- Liñas 26-30: Facemos uso do método onItemSelected() e os seus parámetros para obter o dato da lista seleccionado.
Caso práctico 2: Usando un array estático en Java
- Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_02_Spinners de tipo Launcher e sen compatibilidade.
- Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.
- Neste caso cargaremos a fonte de datos dun array local.
O código XML da activity é:
1 <?xml version="1.0" encoding="utf-8"?>
2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context=".Adaptadores.UD04_02_Spinners">
8
9 <Spinner
10 android:id="@+id/spnLista_UD04_02_Spinner"
11 android:layout_width="wrap_content"
12 android:layout_height="wrap_content"
13 android:layout_marginBottom="8dp"
14 android:layout_marginEnd="8dp"
15 android:layout_marginStart="8dp"
16 android:layout_marginTop="8dp"
17 app:layout_constraintBottom_toBottomOf="parent"
18 app:layout_constraintEnd_toEndOf="parent"
19 app:layout_constraintStart_toStartOf="parent"
20 app:layout_constraintTop_toTopOf="parent" />
21 </android.support.constraint.ConstraintLayout>
- Ao final do código explícase como se enlaza a fonte de datos co adaptador e este co spinner.
- Observar as liñas marcadas.
1 package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.view.View;
6 import android.widget.AdapterView;
7 import android.widget.ArrayAdapter;
8 import android.widget.Spinner;
9 import android.widget.TextView;
10 import android.widget.Toast;
11
12 import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
13
14 public class UD04_02_Spinners extends Activity {
15
16 private void cargarLista(){
17
18 Spinner spinFroitas = (Spinner) findViewById(R.id.spnLista_UD04_02_Spinner);
19
20 // Fonte de datos
21 String[] froitas = new String[] { "Pera", "Mazá", "Plátano" };
22
23 // Enlace do adaptador cos datos
24 ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, froitas);
25
26 // Opcional: layout usuado para representar os datos no Spinner
27 adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
28
29 // Enlace do adaptador co Spinner do Layout.
30 spinFroitas.setAdapter(adaptador);
31
32 // Escoitador
33 spinFroitas.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
34 @Override
35 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
36 //Toast.makeText(getBaseContext(), "Seleccionaches: " + parent.getItemAtPosition(pos), Toast.LENGTH_LONG).show();
37 Toast.makeText(getBaseContext(), "Seleccionaches: " + ((TextView) view).getText(), Toast.LENGTH_LONG).show();
38
39 }
40
41 @Override
42 public void onNothingSelected(AdapterView<?> arg0) {
43 // TODO Auto-generated method stub
44 }
45 }); // Fin da clase anónima
46
47 }
48
49
50 @Override
51 protected void onCreate(Bundle savedInstanceState) {
52 super.onCreate(savedInstanceState);
53 setContentView(R.layout.activity_ud04_02__spinners);
54
55 cargarLista();
56 }
57 }
- Liña 23: Definimos a fonte de datos, neste caso un array estático.
- Liña 26: Definimos o adaptador de tipo ArrayAdapter. Pasámoslle como parámetros:
- Contexto,
- O int, identificador de recurso de layout que se vai usar para representar a Vista de Selección, neste caso usamos un predefinido. O usuario pode experimentar con outros tipos (android.R.layout.... CTRL+ESPAZO) e ver que outras formas hai de presentar os datos nun Spinner.
- Un array de obxectos, neste caso de Strings.
- Para ver outros construtores e métodos: http://developer.android.com/reference/android/widget/ArrayAdapter.html
- Liña 29: setDropDownViewResource(int), indica como se vai representar cada un dos ítems do Spinner. Usamos un layout xa predefinido. O usuario pode experimentar usando outros distintos, predefinidos ou propios.
- Liña 32: establece o adaptador que subministra os datos ao Spinner.
- Liña 35: O escoitador é o mesmo que cando non se usaba un adaptador.
- Liñas 38,39: As dúas liñas fan o mesmo, pero no segundo caso observar como recollemos a vista (view) que nos devolve o evento ao premer nun ítem do Spinner. Esa view é do tipo TextView e por iso facemos un cast e logo xa lle podemos aplicar métodos da clase TextView, como getText().
Caso práctico 3: Uso dun array dinámico
- Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_03_Spinners de tipo Launcher e sen compatibilidade.
- Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.
- Neste caso cargaremos a fonte de datos dun array ArrayList. Cando vexamos o acceso a base de datos, os datos virán dunha táboa.
O código XML da activity é:
1 <?xml version="1.0" encoding="utf-8"?>
2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 tools:context=".Adaptadores.UD04_02_Spinners">
8
9 <Spinner
10 android:id="@+id/spnLista_UD04_03_Spinner"
11 android:layout_width="wrap_content"
12 android:layout_height="wrap_content"
13 android:layout_marginBottom="8dp"
14 android:layout_marginEnd="8dp"
15 android:layout_marginStart="8dp"
16 android:layout_marginTop="8dp"
17 app:layout_constraintBottom_toBottomOf="parent"
18 app:layout_constraintEnd_toEndOf="parent"
19 app:layout_constraintStart_toStartOf="parent"
20 app:layout_constraintTop_toTopOf="parent" />
21 </android.support.constraint.ConstraintLayout>
- Nos dous casos anteriores o contido do Spinner é estático e defínese en tempo de compilación, non de execución.
- Se usamos arrays dinámicos podemos crear a fonte de datos en tempo de execución antes de pasarlla ao adaptador.
- Así imos poder usar datos de ficheiros, bases de datos, etc e crear unha fonte de datos para un Spinner en tempo de execución.
1 package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.view.View;
6 import android.widget.AdapterView;
7 import android.widget.ArrayAdapter;
8 import android.widget.Spinner;
9 import android.widget.TextView;
10 import android.widget.Toast;
11
12 import java.util.ArrayList;
13
14 import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
15
16 public class UD04_03_Spinners extends Activity {
17
18 private void cargarLista(){
19
20 Spinner spinFroitas = (Spinner) findViewById(R.id.spnLista_UD04_03_Spinner);
21
22 ArrayList<String> animais = new ArrayList<String>();
23
24 animais.add("CABALLOS");
25 animais.add("GATITOS");
26 animais.add("PERROS");
27 animais.add("RATONES");
28
29 // Enlace do adaptador cos datos
30 ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, animais);
31
32 // Enlace do adaptador co Spinner do Layout.
33 spinFroitas.setAdapter(adaptador);
34
35 // Escoitador
36 spinFroitas.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
37 @Override
38 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
39 //Toast.makeText(getBaseContext(), "Seleccionaches: " + parent.getItemAtPosition(pos), Toast.LENGTH_LONG).show();
40 Toast.makeText(getBaseContext(), "Seleccionaches: " + ((TextView) view).getText(), Toast.LENGTH_LONG).show();
41
42 }
43
44 @Override
45 public void onNothingSelected(AdapterView<?> arg0) {
46 // TODO Auto-generated method stub
47 }
48 }); // Fin da clase anónima
49
50 }
51
52
53 @Override
54 protected void onCreate(Bundle savedInstanceState) {
55 super.onCreate(savedInstanceState);
56 setContentView(R.layout.activity_ud04_03__spinners);
57
58 cargarLista();
59 }
60 }
- Liñas 23-28: Neste caso os elementos do array engádense en tempo de execución ao array animais, que neste caso e do tipo ArrayList.
- O resto é exactamente igual.
Caso práctico 4: Personalizando o deseño
- Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_04_Spinners de tipo Launcher e sen compatibilidade.
- Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.
- Como indicamos dende o inicio, cando creamos o Spinner tamén creamos un adaptador sobre o cal indicamos o layout de cada compoñente da lista.
- Podemos crear nos mesmos o deseño que queiramos cos datos que queiramos que aparezan na lista.
- Para facer o anterior, temos que crear o noso propio adaptador.
- Nesta práctica creamos un layout formado por unha imaxe e un texto para cada elemento da lista do spinner.
- Como o que queremos é facer un deseño específico para cada 'fila' de elementos da lista / spinner, imos crear o Layout que vai representar cada fila:
Nome Arquivo do layout: spinner_ud04_04.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent">
6
7 <ImageView
8 android:id="@+id/imgVImaxen_UD04_04_Spinners"
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content"
11 android:layout_weight="1"
12 />
13
14 <TextView
15 android:id="@+id/txtTexto_UD04_04_Spinners"
16 android:layout_width="wrap_content"
17 android:layout_height="wrap_content"
18 android:layout_weight="2"
19 android:text="TextView" />
20 </LinearLayout>
- Como vemos, estamos a definir un layout cun Imageview e un TextView. Pero poderíamos poñer calquera lauyout con calquera número de elementos e deseño.
- Partimos dun exercicio anterior onte xa tiñamos definidos nun array os datos do exercicio:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <string-array name="planetas_UD02_01_spinner">
5 <item>Mercurio</item>
6 <item>Venus</item>
7 <item>Terra</item>
8 <item>Marte</item>
9 <item>Xúpiter</item>
10 <item>Saturno</item>
11 <item>Urano</item>
12 <item>Neptuno</item>
13 </string-array>
14
15 </resources>
- Agora crearemos o Adaptador.
- Despois de facer o anterior teremos un código coma isto:
- Arquivo: Adaptador_UD04_04_Spinners
1 public class Adaptador_UD04_04_Spinners extends ArrayAdapter {
2
3 public AdaptadorPrueba(@NonNull Context context, int resource) {
4 super(context, resource);
5 }
6 }
- Agora debemos ter claro que o que imos a 'enviar' a este adaptador van ser os datos necesarios para que 'constrúa' a lista de elementos.
- No noso caso, queremos que faga unha lista de elementos no que cada elemento vai ser un texto (TextView) e unha imaxe (ImageView).
- Polo tanto teremos que enviar un array de cadeas (para o texto) e algo para facer unha imaxe. No exemplo imos a enviarlle imaxes gardadas en /res/drawable/ e polo tanto serán un array de enteiros (lembrar que en /res/ todo se referencia por números facendo uso da clase R). Poderíamos enviar URL e que o ImageView cargase a imaxe de dita URL.
- Modificamos o construtor para que recolla estes datos. Como teremos que facer uso deles noutros métodos, crearemos propiedades locais na clase:
1 public class Adaptador_UD04_04_Spinners extends ArrayAdapter {
2
3 int[] imaxes; // Lista de imaxes a cargar. Lembra que en res todo son números Se foran url poderíamos cambialo por String[]
4 String[] textos;
5 Context mContext;
6
7 public Adaptador_UD04_04_Spinners(@NonNull Context context, int[]imaxes,String[]textos) {
8 super(context, R.layout.spinner_ud04_04); // Enviamos o layout que imos utilizar
9
10 this.imaxes = imaxes;
11 this.textos = textos;
12 this.mContext = context;
13 }
14
15 }
- Fixarse na liña 8, que enviamos ao construtor da clase ArrayAdapter o layout que vai 'gardar' cada elemento da lista no spinner.
- Agora, para que funcione o adaptador temos que sobreescribir a lo menos tres métodos:
- int getCount(): Devolve o número de elementos da lista. Fixarse que no noso caso, o número de elementos da lista o sabemos por calquera dos dous arrays onde gardamos os datos. Se creamos catro elementos, a propiedade textos.length será catro.
- View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent): Este método ten que devolver o view de cada elemento da fila. Fixarse que este 'view' no noso caso será un LinearLayout formado por dos Views (un TextView e un ImageView). E o view que visualiza o elemento escollido da lista.
- View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent): Devolve o view que conforma cada elemento da lista cando prememos sobre a mesma (a lista despregable). No exemplo imos amosar o mesmo que en getView (pero non tería por qué ser así).
- Fixarse que no caso dos métodos que devolven un view, podemos facer nos un dinamicamente e devolvelo.
- Por exemplo, se fago isto:
1 @Override
2 public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
3 TextView proba = new TextView(mContext);
4 proba.setText("OOOOOOOO");
5 return proba;
6 }
- Aparece isto:
- Isto sería útil se queremos que cando escollamos un elemento apareza unha información e cando estea escollido apareza outra. Máis información neste enlace.
- No noso caso queremos que visualmente apareza o mesmo cando temos un elemento escollido da lista, como cando aparece o despregable da mesma.
- Como o view que representa o elemento seleccionado da lista o obtemos do método getView (como comentamos antes) o código quedaría así:
1 @Override
2 public int getCount() {
3 return textos.length; // Poderíamos poñer tamén o número de imaxes.
4 }
5
6 @Override
7 public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
8 return getView(position,convertView,parent);
9 }
10
11 @NonNull
12 @Override
13 public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
14 return super.getView(position, convertView, parent);
15 }
- Liña 3: Devolvemos o número de textos enviados como parámetro do constructor.
- Liña 8: Devolvemos o view do método getView que imos a modificar.
- Agora ven o máis importante, que é crear o view que conforma o elemento seleccionado no Spinner:
- O proceso para facelo é o seguinte:
- Fixámonos na definición do método getView: public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- Ese obxecto da clase View vai 'levar' o layout que temos definido para cada elemento da fila.
- E os datos cos que vai encher dito layout van ir no método setTag xa comentado nesta wiki.
- Ese obxecto que aparece como parámetro (convertView) representa o conxunto de elementos gráficos que conforman cada fila do spinner.
- A primeira vez que se chama, ese obxecto vale 'null' e debemos de facer que sexa igual ao layout no que definimos a imaxe e o texto que conforman cada elemento da lista.
- A segunga e seguintes veces, ese dato xa virá co layout asociado.
- O primeiro é cargar o layout no 'convertView'.
- Para iso temos que pasar o layout dun arquivo XML a un obxecto que poida ser empregado en programación.
- Iso se fai facendo un 'inflate':
1 LayoutInflater mInflater = (LayoutInflater) mContext. 2 getSystemService(Context.LAYOUT_INFLATER_SERVICE); 3 convertView = mInflater.inflate(R.layout.spinner_ud04_04, parent, false);
- Xa analicaremos en detalle este código. Por agora quedade coa idea de que estas liñas fan que o LinearLayout co botón e a imaxe pasa a ser un obxecto que se garda en convertView.
- Como dixemos antes, isto soamente hai que facelo se o convertView ven cun valor null.
1 @Override
2 public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
3
4 if (convertView == null) {
5
6 LayoutInflater mInflater = (LayoutInflater) mContext.
7 getSystemService(Context.LAYOUT_INFLATER_SERVICE);
8 convertView = mInflater.inflate(R.layout.spinner_ud04_04, parent, false);
9 }
10 .............
11 }
- Segundo, debemos pasar os datos a cada un dos elementos gráficos que se atopan no obxecto 'convertView'.
- Para iso podemos empregar o método findViewById no convertView. O único que temos que facer é buscar cada compoñente gráfico e asociarlle o dato que sabemos cal é polo parámetro 'int position', que indica a posición do elemento da lista seleccionado.
1 @Override 2 public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 3 4 if (convertView == null) { 5 6 LayoutInflater mInflater = (LayoutInflater) mContext. 7 getSystemService(Context.LAYOUT_INFLATER_SERVICE); 8 convertView = mInflater.inflate(R.layout.spinner_ud04_04, parent, false); 9 } 10 ((ImageView)convertView.findViewById(R.id.imgVImaxen_UD04_04_Spinners)).setImageResource(imaxes[position]); 11 ((TextView) convertView.findViewById(R.id.txtTexto_UD04_04_Spinners)).setText(textos[position]); 12 13 return convertView; 14 15 }
- Nota: Lembrar que como xa vimos no caso do ImageView, podemos empregar os métodos getTag() e setTag() para enviar datos e asocialos a un view.
- Unha vez que temos o adaptador creado teremos que ir á activity e asociar o spinner a dito adaptador.
- Como non temos moitas imaxes en /res/ imos asociar a mesma imaxe a todos os elementos da lista. Partimos que temos unha imaxe en res de nome: R.drawable.ok (se non é o caso poñede outra calquera).
Arquivo: UD04_04_Spinners
1 package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.widget.Spinner;
6
7 import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
8
9 public class UD04_04_Spinners extends Activity {
10
11 private void cargarLista(){
12 String datos[] = getResources().getStringArray(R.array.planetas_UD02_01_spinner);
13 int[] imaxes = new int[datos.length];
14 for(int cont=0;cont<datos.length;cont++){
15 imaxes[cont]=R.drawable.ok;
16 }
17
18 Spinner lista = findViewById(R.id.spnLista_UD04_04_Spinner);
19
20 Adaptador_UD04_04_Spinners meuAdaptador = new Adaptador_UD04_04_Spinners(this,imaxes,datos);
21 lista.setAdapter(meuAdaptador);
22
23 }
24
25 @Override
26 protected void onCreate(Bundle savedInstanceState) {
27 super.onCreate(savedInstanceState);
28 setContentView(R.layout.activity_ud04_04__spinners);
29
30 cargarLista();
31 }
32 }
-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2018).