• Non ci sono risultati.

5.3 Realizzazione

5.3.3 Selezione

Una volta accettate le condizioni, il programma dovrà far scegliere all'utente la città, la compagnia, la modalità ecc... In breve dovrà far compiere all'u-tente tante scelte multiple. Creiamo quindi un layout standard per la scelta multipla.

Layout scelta multipla Voglio creare un oggetto che mi mostri una lista di elementi selezionabili, come ad esempio un elenco di città. Appena tocco uno degli oggetti della lista questo si deve evidenziare, e alla pressione del tasto conferma devo essere in grado di capire quale o quali elementi sono stati selezionati.

Come prima cosa creo un nuovo tipo di oggetto, l'oggetto vista<E> che implementa l'interfaccia Serializable1. La <E> indica che è un oggetto generico, ovvero uno o più dei suoi campi sarà un oggetto non denito a priori. Vediamone il listato.

1 c l a s s v i s ta <E> implements S e r i a l i z a b l e { /∗∗ 3 ∗/ 5 p r i v a t e s t a t i c f i n a l long serialVersionUID = 1L ; p u b l i c S t r i n g testo , d e s c r i z i o n e ;

1Il motivo per cui l'oggetto estende l'interfaccia Serializable è che in tal modo è possibile inviarlo attraverso le varie Activity

7 p u b l i c E ogg ;

p u b l i c Bitmap img ;

9 p u b l i c boolean f r e c c i a ;

p u b l i c i n t quantita ;

11

p u b l i c v i s t a ( S t r i n g testo , S t r i n g d e s c r i z i o n e , E ogg , Bitmap image ,boolean f r e c c i a ,i n t quantita ) {

13 t h i s. t e s t o=t e s t o ; t h i s. ogg=ogg ; 15 img=image ; t h i s. f r e c c i a=f r e c c i a ; 17 t h i s. d e s c r i z i o n e=d e s c r i z i o n e ; t h i s. quantita=quantita ; 19 }

p u b l i c v i s t a ( S t r i n g testo , E ogg , Bitmap image ,boolean

f r e c c i a ) {

21 t h i s( testo ,null , ogg , image , f r e c c i a , −1) ;

23 }

25 }

Nelle variabili di istanza ne abbiamo due di tipo String testo e descrizione che conterranno rispettivamente il testo che verrà visualizzato nella lista che poi creeremo e un eventuale descrizione che comparirà in basso sotto al testo. La variabile ogg è l'oggetto generico. Vedremo in seguito perché ci sarà utile. img è l'eventuale immagine che si accompagna al testo per avere l'interfaccia più accattivante. freccia è un ag che ci dirà se aggiungere o no l'immagine di una freccia nella visualizzazione dell'elemento. quantità è un intero in cui verrà salvata un'eventuale quantità. Ad esempio, se volessimo prendere 2 biglietti dello stesso tipo la variabile sarà impostata su 2.

Ora che abbiamo gli oggetti che deniscono la lista non ci resta che creare gli oggetti graci a partire dall'oggetto vista. Ad assolvere questo compito sarà l'oggetto oggettoLista<E>.

1 a b s t r a c t c l a s s oggettoLista <E>{

p u b l i c s t a t i c S t r i n g VISTA_RETURN=" strBack ";

3 p u b l i c f i n a l v i sta <E> v i s t a ;

protected A c t i v i t y act ;

5 protected RelativeLayout questo ;

p r i v a t e boolean s e l e c t e d ;

7 p u b l i c f i n a l OnClickListener c l i c k ;

p u b l i c o g g e t t o L i s t a ( v i sta <E> v i s t a ) {

9 t h i s. v i s t a=v i s t a ;

13 }

protected RelativeLayout getRelativeLayout ( ViewGroup overview , A c t i v i t y a ) {

15

L a y o u t I n f l a t e r i n f l a t e r =

( L a y o u t I n f l a t e r ) a . getSystemService ( Context .LAYOUT_INFLATER_SERVICE) ;

17 RelativeLayout view = ( RelativeLayout ) i n f l a t e r . i n f l a t e ( R. layout . b o t t o n e f r e c c i a , overview , f a l s e) ;

19 return view ;

21 }

23 p u b l i c OnClickListener getOnClickListener ( ) {

OnClickListener r= new OnClickListener ( ) {

25 p u b l i c void onClick ( View v ) { OnClickListener ( v ) ;

27 } } ;

29 return r ; }

31 p u b l i c a b s t r a c t void OnClickListener ( View v ) ;

p u b l i c void f i n i s h ( ) {

33 act . f i n i s h ( ) ; }

35 p u b l i c void r i t o r n a V i s t a ( vi sta <E> s ) { Intent i n t e n t=act . g e t I n t e n t ( ) ; 37 i n t e n t . putExtra (VISTA_RETURN, s ) ; act . s e t R e s u l t ( A c t i v i t y .RESULT_OK, i n t e n t ) ; 39 f i n i s h ( ) ; } 41 protected Intent g e t I n t e n t ( ) { return act . g e t I n t e n t ( ) ; 43 }

p u b l i c View c r e a V i s t a ( A c t i v i t y a , ViewGroup overview ) {

45

act=a ;

47

RelativeLayout view = getRelativeLayout ( overview , a ) ;

49 questo=view ; 51 aggiornaVista ( ) ; return view ; 53 } p u b l i c void aggiornaVista ( ) { 55 RelativeLayout view=questo ; i f( v i s t a . img==n u l l) {

57 view . removeView ( view . findViewById ( R. id . immagineElemento ) ) ;

}

59 e l s e{

( ( ImageView ) view . findViewById (R. id . immagineElemento ) ) . setImageBitmap ( v i s t a . img ) ;

61 }

i f( ! v i s t a . f r e c c i a ) {

63 view . removeView ( view . findViewById (R. id . immagineFreccia ) ) ; }

65 ( ( TextView ) view . findViewById (R. id . t e s t o ) ) . setText ( v i s t a . t e s t o ) ; view . s e t C l i c k a b l e (true) ;

67 view . se t O nCl i c k Li ste ne r (new OnClickListener ( ) {

p u b l i c void onClick ( View v ) {

69 OnClickListener ( v ) ; 71 } 73 }) ; } 75 p r i v a t e Drawable prev ; p u b l i c void s e l e c t (boolean s e l e c t ) { 77 t h i s. s e l e c t e d=s e l e c t ; i f( s e l e c t ) { 79 prev=questo . getBackground ( ) ;

questo . setBackgroundColor ( Color .YELLOW) ;

81 }

e l s e{

83 questo . setBackgroundDrawable ( prev ) ;

85 } }

87 p u b l i c boolean i s S e l e c t e d ( ) {

return s e l e c t e d ;

89 }

p u b l i c LinkedList <vi sta <E>> g e t L i s t a ( ) {

91 I t e r a t o r <oggettoLista <E>> i= s e l e c t e d . i t e r a t o r ( ) ; LinkedList <v i st a <E>> r e t= new LinkedList <v i sta <E>>() ;

93 while( i . hasNext ( ) ) {

oggettoLista <E> r=i . next ( ) ;

95 r e t . add ( r . v i s t a ) ; }

97 return r e t ;

99 } }

Come vediamo nel listato ho creato una classe astratta 2, lasciando come unico metodo da implementare onClickListener.

Lo scopo di questo oggetto è di creare una view che rappresenti graca-mente l'oggetto Vista passato nel costruttore(metodo creaVista(Activity, ViewGroup)), che sia possibile selezionarlo (metodo select()) e che sia possibile capire se è stato selezionato (metodo isSelected()).

Il metodo aggiornaVista() consente di aggiornare la graca della vista stessa in base all'oggetto passato.

RitornaVista() invece termina l'Activity restituendo l'oggetto vista pas-sato al costruttore.

Ora che abbiamo gli oggetti per creare un elemento della lista possiamo creare la lista vera e propria.

Ogni lista selezionabile avrà le sue caratteristiche. Procedendo con ordine, vediamo come realizzare la prima, ovvero quella di scelta della città. La schermata prevede che l'utente possa scegliere, tramite tocco, una e una sola città dall'elenco.

Prima di realizzare la lista selezionabile creiamo una classe che mostri semplicemente un elenco di oggettoLista che verrà poi esteso per realizzare le liste di cui abbiamo bisogno.

Il codice, davvero molto semplice, è il seguente p u b l i c c l a s s listaView <E> extends ScrollView {

2 protected oggettoLista <E>[] l i s t a ;

protected l i s t a V i e w ( A c t i v i t y a c t i v i t y ) { 4 super( a c t i v i t y . getApplicationContext ( ) ) ; } 6 p u b l i c l i s t a V i e w ( oggettoLista <E>[] l i s t a s , A c t i v i t y a c t i v i t y ) { super( a c t i v i t y . getApplicationContext ( ) ) ; 8 i f( l i s t a s==n u l l) {

throw new IllegalArgumentException (" La v a r i a b i l e l i s t a s non può e s s e r e n u l l ") ;

10 }

c r e a L i s t a ( l i s t a s , a c t i v i t y ) ;

12 }

protected void c r e a L i s t a ( oggettoLista <E>[] l i s t a s , A c t i v i t y a c t i v i t y ) {

14 l i s t a=l i s t a s ;

LinearLayout l= new

LinearLayout ( a c t i v i t y . getApplicationContext ( ) ) ;

2Si dice classe astratta una classe che denisce un'interfaccia senza implementarla com-pletamente. Ciò serve come base di partenza per generare una o più classi specializzate aventi tutte la stessa interfaccia di base. Queste potranno poi essere utilizzate indieren-temente da applicazioni che conoscono l'interfaccia base della classe astratta, senza sapere niente delle specializzate.(Wikipedia)

16 l . s e t O r i e n t a t i o n ( LinearLayout .VERTICAL) ;

f o r( oggettoLista <E> l i s : l i s t a ) {

18 l . addView ( l i s . c r e a Vi s t a ( a c t i v i t y , t h i s) ) ; }

20 addView ( l ) ;

l . getLayoutParams ( ) . height=LayoutParams .WRAP_CONTENT;

22 l . getLayoutParams ( ) . width=LayoutParams .FILL_PARENT;

}

24 }

Cominciamo notando che questa classe estende ScroolView (già visto in 3.6.1), dunque ci aspettiamo un layout a scorrimento.

Come si evince dal codice, il costruttore non si limita a controllare che la variabile listas sia diversa da null e chiama il metodo creaLista. Quest'ulti-mo inserisce all'interno del layout le viste generate dal comando creaVista del-la cdel-lasse oggettoLista. Le ultime due righe del metodo servono a dimensionare la lista view e hanno la stessa funzionalità dei comandi android:layout_width e android:layout_width nel le xml spiegati in 3.3.2.

Realizziamo ora la lista selezionabile di cui avevamo bisogno. Ovviamente la classe estenderà quella appena vista. Eccone il listato:

c l a s s s e l e c t a b l e L i s t a V i e w <E> extends listaView <E>{

2 p r i v a t e i n t maxSelectable ;

p r i v a t e LinkedList <oggettoLista <E>> s e l e c t e d ;

4 protected s e l e c t a b l e L i s t a V i e w ( A c t i v i t y a c t i v i t y ) { super( a c t i v i t y ) ; 6 } p u b l i c s e l e c t a b l e L i s t a V i e w ( vi sta <E>[] v i s t e , A c t i v i t y a c t i v i t y ,i n t maxSelecteabl ) { 8 super( a c t i v i t y ) ;

s e l e c t e d= new LinkedList <oggettoLista <E>>() ;

10 t h i s. maxSelectable=maxSelecteabl ; l i s t a = extracted2 ( v i s t e . lenght ) ;

12 f o r(i n t i =0; i<l i s t a . length ; i++){

l i s t a [ i ]= new oggettoLista <E>( v i s t e [ i ] ) {

14 p u b l i c void OnClickListener ( View v ) {

i f( ! i s S e l e c t e d ( ) ) { 16 i f( s e l e c t e d . s i z e ( )>=maxSelectable ) { s e l e c t e d . remove ( ) . s e l e c t (f a l s e) ; 18 } s e l e c t (true) ; 20 s e l e c t e d . add (t h i s) ; } 22 e l s e{ s e l e c t (f a l s e) ; 24 s e l e c t e d . remove (t h i s) ;

} 26 } } ; 28 } c r e a L i s t a ( l i s t a , a c t i v i t y ) ; 30 32 } p u b l i c LinkedList <v i s ta <E>> g e t L i s t a ( ) { 34 I t e r a t o r <oggettoLista <E>> i= s e l e c t e d . i t e r a t o r ( ) ; LinkedList <v i st a <E>> r e t= new LinkedList <vista <E>>() ;

36 while( i . hasNext ( ) ) {

oggettoLista <E> r=i . next ( ) ;

38 r e t . add ( r . v i s t a ) ; }

40 return r e t ;

42 }

p u b l i c void s e t S e l e c t e d L i s t a ( LinkedList <v is ta <E>> v ) {

44 I t e r a t o r <v i sta <E>> i= v . i t e r a t o r ( ) ;

while( i . hasNext ( ) ) {

46 v i s ta <E> n=i . next ( ) ;

oggettoLista <E> o= trovamiOggettoLista (n) ;

48 o . s e l e c t (true) ; s e l e c t e d . add ( o ) ;

50 } }

52 p r i v a t e oggettoLista <E> trovamiOggettoLista ( v is t a <E> n) {

f o r(i n t i =0; i<l i s t a . length ; i++){

54 i f( l i s t a [ i ] . v i s t a . equals (n) ) { return l i s t a [ i ] ; 56 } 58 } return n u l l; 60 } p u b l i c s e l e c t a b l e L i s t a V i e w ( v i sta <E>[] v i s t e , A c t i v i t y a c t i v i t y ,i n t maxSelecteabl ,boolean r i e p i l o g o ) { 62 super( a c t i v i t y ) ;

s e l e c t e d= new LinkedList <oggettoLista <E>>() ;

64 t h i s. maxSelectable=maxSelecteabl ;

oggettoRiepilogo <E>[] l i s t a = e x t r a c t e d ( v i s t e ) ;

66

f o r(i n t i =0; i<l i s t a . length ; i++){

68 l i s t a [ i ]= new oggettoRiepilogo <E>( v i s t e [ i ] ) {

p u b l i c void OnClickListener ( View v ) {

70 i f ( ! i s S e l e c t e d ( ) ) {

i f( s e l e c t e d . s i z e ( )>=maxSelectable ) {

} 74 s e l e c t (true) ; s e l e c t e d . add (t h i s) ; 76 } e l s e{ 78 s e l e c t (f a l s e) ; s e l e c t e d . remove (t h i s) ; 80 } 82 } 84 } ; } 86 c r e a L i s t a ( l i s t a , a c t i v i t y ) ; } 88 @SuppressWarnings (" unchecked ")

p r i v a t e oggettoRiepilogo <E>[] e x t r a c t e d ( vi sta <E>[] v i s t e ) {

90 return ( oggettoRiepilogo <E> [ ] )new

o g g e t t o R i e p i l o g o [ v i s t e . length ] ; }

92 @SuppressWarnings (" unchecked ")

p r i v a t e oggettoLista <E>[] extracted2 ( vi s ta <E>[] v i s t e ) {

94 return ( oggettoLista <E> [ ] )new o g g e t t o L i s t a [ v i s t e . length ] ; }

96 p u b l i c LinkedList <oggettoLista <E>> g e t S e l e c t e d O g g e t t o L i s t a ( ) { LinkedList <oggettoLista <E>> r e t=new

LinkedList <oggettoLista <E>>() ;

98 I t e r a t o r <oggettoLista <E>> i=s e l e c t e d . i t e r a t o r ( ) ;

while( i . hasNext ( ) ) { 100 r e t . add ( i . next ( ) ) ; } 102 return r e t ; } 104 }

Questa classe ha due costruttori pubblici, ma cominciamo analizzando solo il primo. Per ogni oggetto di tipo vista passato nel costruttore vediamo che viene creato un oggetto di tipo oggettoLista. Siccome oggettoLista è un oggetto di tipo astratto, devo implementare i metodi non implementati, in questo caso: OnClickListener. In questa maniera se l'oggetto non è già selezionato, ad ogni click, si aggiunge alla LinkedList selected. Se la lista ha già raggiunto il numero massimo di elementi viene rimosso il primo per fare spazio al nuovo arrivato. Se invece viene cliccato un elemento già selezionato, questo viene deselezionato e rimosso da selected.

salvare lo {stato| della lista (ovvero fare in modo di ricordare cosa è stato selezionato e ripristinarlo). Questi metodi sono importanti per non perdere la selezione mentre si ruota lo schermo3. Il metodo getLista inoltre è utile per ottenere la lista degli elementi selezionati.

Il metodo getSelectedOggettoLista() ci restituisce una copia della lista concatenata contenente gli oggettoLista selezionati.

Il secondo costruttore è praticamente identico al primo, con l'unica die-renza avere oggettoLista al posto di oggettoRiepilogo. Vedremo in seguito a cosa servirà.

Adesso che abbiamo i vari metodi per generare il layout a scelta multipla non ci resta che utilizzarlo: partendo da un array di String -che vedremo in seguito come ottenere- creiamo un array di vista<String> per ogni città impostando le variabili nome e ogg4 con il nome della città.

A questo punto invochiamo il costruttore di selectableListaView passan-dogli come parametro l'array di viste e aggiungendo la vista al layout, si ottiene una schermata come quella della gura 5.3.

Alla pressione del tasto continua viene invocato il metodo getLista per ottenere l'oggetto vista in cui è scritto quale città è stata selezionata; que-st'ultimo inne viene inviato all'Activity successiva (in questo caso scegli-CompagniaActivity) come illustrato in 3.3.4

Documenti correlati