Autore Topic: Come funziona layout_weight?  (Letto 4826 volte)

Offline lucrus

  • Nuovo arrivato
  • *
  • Post: 13
  • Respect: +3
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S GT-I9000 + Olipad + Zenithink ZT-181
  • Sistema operativo:
    Ubuntu 11.04
Come funziona layout_weight?
« il: 13 Giugno 2011, 08:19:17 CEST »
0
Ciao a tutti,

devo fare un layout diviso in tre zone, top, center e bottom. top e bottom sono due immagini che occupano uno spazio fisso sul display. Queste immagini me le fornisce il grafico di turno e non voglio chiodare la loro dimensione nel codice o nell'xml (quindi no AbsoluteLayout). La zona centrale deve essere una GridView che occupa tutto lo spazio restante sul display una volta messe top e bottom. Le view interne alla grid vengono aggiunte da codice a posteriori e quindi non è possibile dimensionare la grid a priori inserendole nel file xml.

Ho pensato ad un LinearLayout verticale ed i primi tentativi erano "along the lines of":

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical">
    <FrameLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:id="@+id/topwizardricerca"
          android:foreground="@drawable/sfondo_ricerca_top"
   />
        <GridView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/wizardgrid"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:numColumns="auto_fit"
            android:verticalSpacing="10dp"
            android:horizontalSpacing="10dp"
            android:columnWidth="90dp"
            android:stretchMode="columnWidth"
           android:background="@drawable/sfondo_ricerca_center"
           android:layout_weight="1"
        />
    <FrameLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:foreground="@drawable/sfondo_ricerca_bottom"
         android:layout_weight="1000"
   />
</LinearLayout>

Il ragionamento era: "se il bottom pesa mille volte di più del center, android dovrà per forza dedicargli 1000 volte di più lo spazio extra sul display, quindi è come dire che sarà almeno certamente visualizzato". Il risultato invece era che il bottom spariva completamente ed il center occupava tutto lo spazio fino al fondo del display...

Per tentativi sono arrivato alla soluzione, ovvero specificare layout_weight solo per il center:

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical">
    <FrameLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:id="@+id/topwizardricerca"
          android:foreground="@drawable/sfondo_ricerca_top"
   />
        <GridView xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/wizardgrid"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:numColumns="auto_fit"
            android:verticalSpacing="10dp"
            android:horizontalSpacing="10dp"
            android:columnWidth="90dp"
            android:stretchMode="columnWidth"
           android:background="@drawable/sfondo_ricerca_center"
           android:layout_weight="1"
        />
    <FrameLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:foreground="@drawable/sfondo_ricerca_bottom"
   />
</LinearLayout>

però non posso dire di aver capito per quale motivo così funziona... qualcuno me lo spiega? Ho letto la poca documentazione che ho trovato ma non ho capito la logica, perché da quello che leggo qui http://developer.android.com/guide/topics/ui/layout-objects.html mi sembra che specificando 1000 come weight la view non dovrebbe sparire.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Come funziona layout_weight?
« Risposta #1 il: 13 Giugno 2011, 08:53:24 CEST »
0
Vado di fretta, non ho letto bene il tuo esempio specifico, ma ti scrivo come funziona il layout_weight.

Il modo migliore di farlo è impersonare android e dirti cosa fa:
1) Alloca lo spazio per le View senza layout_weight secondo le dimensioni layout_width e layout_height
2) Alloca lo spazio per le View con layout_weight secondo le dimensioni layout_width e layout_height
3) Lo spazio rimanente viene allocato per le View con layout_weight in proporzione a layout_weight

C'è una sola particolarità di questo algoritmo che non è immediatamente comprensibile: Ammettiamo di avere e View con layout_weight=1 e layout_width=0dip, in tal caso lo spazio viene diviso equamente tra le tre View in orizzontale. Sempre con layout_weight=1 per tutte e tre, se mettiamo però layout_width="wrap_content", il risultato cambia moltissimo, perchè prima viene allocato lo spazio per il contenuto e dopo solo il rimanente viene equamente diviso.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline lucrus

  • Nuovo arrivato
  • *
  • Post: 13
  • Respect: +3
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S GT-I9000 + Olipad + Zenithink ZT-181
  • Sistema operativo:
    Ubuntu 11.04
Re:Come funziona layout_weight?
« Risposta #2 il: 13 Giugno 2011, 12:31:31 CEST »
0
Ok grazie, ora l'algoritmo è chiaro... MA, c'è sempre un ma. Ho cantato vittoria troppo presto.

Nell'anteprima del layout di Eclipse tutto si vede come dovrebbe usando il secondo file XML che ho postato, con i FrameLayout top e bottom che occupano esattamente la dimensione dell'immagine che contengono e la GridView che, anche se vuota, occupa tutto il resto dello schermo fra i due.

Nel momento in cui provo ad eseguire l'applicazione sul Galaxy S, riempiendo la GridView con un ArrayAdapter, ottengo il top ed il bottom allungati più del necessario, le immagini che contengono stretchate per occupare lo spazio aggiuntivo e la GridView più piccola del necessario (contiene molti elementi ed ha una scrollbar verticale, non capisco perché non le venga dedicato tutto lo spazio possibile).

Ho già provato a mettere la weight della GridView a 10 e a 100 ma non è cambiato nulla... suggerimenti?

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Come funziona layout_weight?
« Risposta #3 il: 13 Giugno 2011, 13:42:24 CEST »
0
Nel momento in cui provo ad eseguire l'applicazione sul Galaxy S, riempiendo la GridView con un ArrayAdapter, ottengo il top ed il bottom allungati più del necessario, le immagini che contengono stretchate per occupare lo spazio aggiuntivo e la GridView più piccola del necessario (contiene molti elementi ed ha una scrollbar verticale, non capisco perché non le venga dedicato tutto lo spazio possibile).

Ho già provato a mettere la weight della GridView a 10 e a 100 ma non è cambiato nulla... suggerimenti?

Il problema non sembra essere della GridView, ma dei FrameLayout. Pare cioè che in fase di creazione del layout, il sistema operativo non riesca a valutare bene le dimensioni del contenuto dei FrameLayout, probabilmente perchè dentro non c'è niente e allora deve calcolarsi le dimensioni in qualche altro modo. Prova a rimuovere il "foreground" e vedi cosa fa, prova poi a metterci dentro una textview con un testo (sempre senza foreground) e vedi cosa fa.

Una domanda: puoi mettere una ImageView al posto del FrameLayout?

Infine: io toglierei i fill_parent dall'unico elemento con il layout_weight, sono attributi contrastanti.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline lucrus

  • Nuovo arrivato
  • *
  • Post: 13
  • Respect: +3
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S GT-I9000 + Olipad + Zenithink ZT-181
  • Sistema operativo:
    Ubuntu 11.04
Re:Come funziona layout_weight?
« Risposta #4 il: 13 Giugno 2011, 14:32:04 CEST »
0
Il problema non sembra essere della GridView, ma dei FrameLayout. Pare cioè che in fase di creazione del layout, il sistema operativo non riesca a valutare bene le dimensioni del contenuto dei FrameLayout, probabilmente perchè dentro non c'è niente e allora deve calcolarsi le dimensioni in qualche altro modo. Prova a rimuovere il "foreground" e vedi cosa fa, prova poi a metterci dentro una textview con un testo (sempre senza foreground) e vedi cosa fa.

Rimuovendo il foreground la dimensione collassa a zero. Aggiungendo una TextView la dimensione diventa quella della TextView (che però non voglio dover aggiungere, è chiaramente una pezza che anche se trovassi il modo di cucire adesso è destinata a creare problemi in futuro). Mettendo sia il foreground sia la TextView, si comporta esattamente come con il foreground ma senza TextView, ovvero in Eclipse visualizza bene ma sul cellulare i FrameLayout vengono allungati.

Una domanda: puoi mettere una ImageView al posto del FrameLayout?

Sì potrei. Ho provato: succede che non viene allungato niente (quindi bene fin qui). Purtroppo però lo spazio extra non viene dato a nessuna delle View, nemmeno alla GridView che ha la weight impostata. Risultano quindi delle bande vuote sullo schermo che mostrano lo sfondo della Activity.

Infine: io toglierei i fill_parent dall'unico elemento con il layout_weight, sono attributi contrastanti.

Se tolgo fill_parent devo metterci qualcos'altro, altrimenti mi lancia un'eccezione perché non trova gli attributi layout_width e layout_height.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
Re:Come funziona layout_weight?
« Risposta #5 il: 13 Giugno 2011, 15:08:33 CEST »
0
Se tolgo fill_parent devo metterci qualcos'altro, altrimenti mi lancia un'eccezione perché non trova gli attributi layout_width e layout_height.

Metti 0dip, così in fase preliminare di allocazione dello spazio (fasi 1 e 2) l'oggetto non influisce in nessun modo sul layout.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline lucrus

  • Nuovo arrivato
  • *
  • Post: 13
  • Respect: +3
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S GT-I9000 + Olipad + Zenithink ZT-181
  • Sistema operativo:
    Ubuntu 11.04
Re:Come funziona layout_weight?
« Risposta #6 il: 13 Giugno 2011, 16:00:22 CEST »
0
Ho risolto. Non ho provato con 0dip perché nel frattempo ho trovato un'altra soluzione, ovvero impostare l'attributo

Codice (XML): [Seleziona]
android:adjustViewBounds="true"
nelle ImageView. Neanche questo ho capito perché funziona, ma l'ho trovato su internet e mi sono fidato...