Autore Topic: ImageView con sovrapposizione di drawables o bitmap  (Letto 1801 volte)

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
ImageView con sovrapposizione di drawables o bitmap
« il: 08 Aprile 2013, 17:31:38 CEST »
0
Ciao a tutti,
sto sbattendo la testa per capire come poter realizzare graficamente una cosa simile a questa:


Mi spiego meglio ...

Nell'esempio qui sopra c'è un semaforo con i 3 stati che conosciamo bene (con i classici 3 colori: verde - giallo - rosso).

Ipotizzate una cosa simile ma anziche avere 3 posizioni (e 3 stati con i soliti 3 colori) troviate un semaforo con 10 posizioni ma con tutti gli stati possibili (e di un solo colore).
Praticamente un codice binario di 10 posizioni: 0 - 1 - 0 - 1 - 1 ecc

Io ho realizzato graficamente il "pannello" per lo sfondo che ospiterà le 10 "lampade" luminose e le "lampade" luminose (accese e spente) in diversi colori.
Ho letto un pò sul forum ed ho trovato, come soluzione, LayerDrawable. Purtroppo però mi costringerebbe a creare decine di file xml con i layer-list per ognuno degli stati delle 10 posizioni.

Quindi avrei pensato ad una cosa simile:
- Disegno il pannello
- Sovrappongo tante lampade (accese o spente) per quante solo le posizioni disponibili nel pannello (con gli opportuni offset)

Spero di essere stato abbastanza chiaro  :-)
Esiste un modo agile per ottenere questo risultato?
Se ti sono stato utile premi "Thanks" ;-)

Offline Giamme

  • Nuovo arrivato
  • *
  • Post: 43
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    HTC Magic
  • Play Store ID:
    appLOOPiamo
  • Sistema operativo:
    Windows 7
"Tutto ciò che è necessario per il trionfo del male è che gli uomini buoni non facciano nulla."
Edmund Burke

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #2 il: 08 Aprile 2013, 23:30:44 CEST »
0
Grazie Giamme ma non credo sia questa la soluzione, citando le prime righe della documentazione ufficiale:
"The image stream may come from either camera preview or video decode"
Puoi essere più preciso eventualmente?

Direi che non è il mio caso, credo sia molto più semplice ma forse mi sto perdendo in un bicchier d'acqua ...
Io in fondo ho a che fare con semplici png in drawable  :-[
Qualuno ha altre idee?
Se ti sono stato utile premi "Thanks" ;-)

Offline NanoAndroide

  • Utente junior
  • **
  • Post: 63
  • Respect: +3
    • Google+
    • Mostra profilo
    • MeToo
  • Dispositivo Android:
    GT-S5570
  • Play Store ID:
    MeToo
  • Sistema operativo:
    Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #3 il: 09 Aprile 2013, 02:44:45 CEST »
0
Non so se ho capito bene, ma secondo me si può fare con una custom view:

Codice (Java): [Seleziona]
public class TrafficlightView extends View {

        Paint paint;
        int posizione;

        public TrafficlightView(Context context, AttributeSet attrs) {
                super(context, attrs);
                init();
        }
       
        private void init() {
                paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(2);
            paint.setColor(Color.WHITE);
        }

        @Override
        protected void onDraw(Canvas canvas) {
           
                int xStep = getMeasuredWidth() / 10;
                int yPoint = getMeasuredHeight()/2;
                int radius = (int) (.9*yPoint);
            canvas.drawCircle(xStep*posizione, yPoint, radius, paint);     
           
        }

        public void update(int posizione) {
            this.posizione = posizione;
            invalidate();
        }

}

Se ad una data posizione corrisponde un solo colore, basta cambiare il colore con cui disegna 'la lampada' in funzione della posizione, altrimenti aggiungere un parametro a update per determinare lo stato/colore...

p.s.: nell'esempio l'orientamento è orizzontale, ma basta cambiare x con y...  ;-)
p.p.s.: puoi attribuire il background via xml ed il gioco è fatto... :-)

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #4 il: 09 Aprile 2013, 11:33:02 CEST »
0
Ciao NanoAndroide, intanto grazie.
Il problema è proprio il fatto di usare dei drawable (dei file png) e non di disegnare su canvas.

Nel frattempo ho provato così:

Codice (XML): [Seleziona]
    <ImageView
       android:id="@+id/testimage"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:src="@drawable/panel"
        android:contentDescription="@string/app_name" />
 

Codice (Java): [Seleziona]
                testimage = (ImageView) findViewById (R.id.testimage);
                Resources r = getResources();
                Drawable[] layers = new Drawable[3];
                layers[0] = r.getDrawable(R.drawable.panel);
                layers[1] = r.getDrawable(R.drawable.led_off);
                layers[2] = r.getDrawable(R.drawable.led_on);
               
                LayerDrawable layerDrawable = new LayerDrawable(layers);
                testimage.setImageDrawable(layerDrawable);

Mi sarei aspettato di vedere il pannello ed un led (i layers [1] e [2] si sovrapporrebbero immagino) acceso (visto che l'ultimo layer è R.drawable.led_on) ...
Purtroppo l'emulatore mi restituisce una pagina con il giusto layout ma completamente bianca  ???
Se ti sono stato utile premi "Thanks" ;-)

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #5 il: 09 Aprile 2013, 11:45:15 CEST »
0
Penso che la soluzione più sensata, anche in termini di risorse, sia quella di fare una custom imageview.
Nel file xml ci metti la custom imageview e carichi lo "sfondo" del semaforo.
Poi nella tua classe carichi i led separati e li disegni...

Offline NanoAndroide

  • Utente junior
  • **
  • Post: 63
  • Respect: +3
    • Google+
    • Mostra profilo
    • MeToo
  • Dispositivo Android:
    GT-S5570
  • Play Store ID:
    MeToo
  • Sistema operativo:
    Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #6 il: 09 Aprile 2013, 12:16:00 CEST »
0
Ciao NanoAndroide, intanto grazie.
Il problema è proprio il fatto di usare dei drawable (dei file png) e non di disegnare su canvas.

Nel frattempo ho provato così:

Codice (XML): [Seleziona]
    <ImageView
       android:id="@+id/testimage"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:src="@drawable/panel"
        android:contentDescription="@string/app_name" />
 

Codice (Java): [Seleziona]
                testimage = (ImageView) findViewById (R.id.testimage);
                Resources r = getResources();
                Drawable[] layers = new Drawable[3];
                layers[0] = r.getDrawable(R.drawable.panel);
                layers[1] = r.getDrawable(R.drawable.led_off);
                layers[2] = r.getDrawable(R.drawable.led_on);
               
                LayerDrawable layerDrawable = new LayerDrawable(layers);
                testimage.setImageDrawable(layerDrawable);

Mi sarei aspettato di vedere il pannello ed un led (i layers [1] e [2] si sovrapporrebbero immagino) acceso (visto che l'ultimo layer è R.drawable.led_on) ...
Purtroppo l'emulatore mi restituisce una pagina con il giusto layout ma completamente bianca  ???

Non so bene come funzionino i LayerDrawable, non mi è mai capitato di sentirne il bisogno...  :-[
Immagino che ci sia qualche metodo per impostare la visibilità del singolo layer...

Tuttavia, come suggerivo prima e come ha confermato anche undead, la via più pratica passa per l'uso di una custom view (o una più specializzata imageView). Una volta creata, non sarebbe più necessario scrivere direttamente su Canvas, ma agire sull'xml per impostare lo sfondo. Continuo con l'esempio di prima:

Codice (XML): [Seleziona]
<com.example.customview.TrafficlightView
       android:id="@+id/semaforo"
       android:layout_width="match_parent"
       android:layout_height="50dp"
       android:background="@drawable/myshape" />

Nell'usarla, basta dirgli in che 'posizione' deve esserci una 'luce':

Codice (Java): [Seleziona]
public class MainActivity extends Activity {

        TrafficlightView tl;
       
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
               
                tl = (TrafficlightView)findViewById(R.id.semaforo);
               
                final myTimer time=new myTimer(10000, 1000);
                time.start();
               
        }
       
        public class myTimer extends CountDownTimer{
               
                int pos;

                public myTimer(long startTime, long interval) {
                        super(startTime, interval);
                        pos=1;
                }

                @Override
                public void onFinish() {
                        finish();
                }

                @Override
                public void onTick(long eTime) {                       
                        tl.updateData(pos);
                        pos+=1;
                }
       
    }
}

L'esempio esegue un ciclo di tutte le posizioni possibili. Ovviamente puoi rimpiazzare il cerchio che nell'esempio rappresenta la luce con un drawable di tuo gusto...  :D

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #7 il: 09 Aprile 2013, 16:08:04 CEST »
0
Rettifico...
la soluzione che ho postato prima funziona (non so per quale arcano motivo prima sull'emulatore non visualizzava correttamente bah).
Il problema però è che ogni layer successivo al primo (il pannello) viene dimensionato come (o eredità le proprietà del) il primo.
Mi spiego meglio ... se il pannello è 100dp x 100dp ed le "luci" sono 5dp x 5dp, le luci verranno mostrate come ridimensionate a 100dp x 100dp.

Sembra vengano ignorate le dimensioni/bordi del drawable  o_O

Vengono però disegnati nella giusta sequenza pannello (sullo sfondo) - luce spenta (invisibile in quanto coperdo dal successivo) - luce accesa (primo piano).

Aiuuuutooo  ???


Codice (XML): [Seleziona]
    <ImageView
       android:id="@+id/testimage"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:src="@drawable/panel"
        android:contentDescription="@string/app_name" />
 

Codice (Java): [Seleziona]
                testimage = (ImageView) findViewById (R.id.testimage);
                Resources r = getResources();
                Drawable[] layers = new Drawable[3];
                layers[0] = r.getDrawable(R.drawable.panel);
                layers[1] = r.getDrawable(R.drawable.led_off);
                layers[2] = r.getDrawable(R.drawable.led_on);
               
                LayerDrawable layerDrawable = new LayerDrawable(layers);
                testimage.setImageDrawable(layerDrawable);

Aggiornamento:
spero di sbagliare, ma qui ne parlano senza grandi risultati: http://jacekdalkowski.wordpress.com/2012/01/30/android-draw-a-number-of-bitmaps-or-drawables-into-a-single-drawable/  ???
« Ultima modifica: 09 Aprile 2013, 16:56:51 CEST da Eu4ia »
Se ti sono stato utile premi "Thanks" ;-)

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #8 il: 09 Aprile 2013, 17:18:37 CEST »
0
Se ti fai una imageview puoi andare a posizionare le cose dove ti pare con le dimensioni che preferisci.
Ti fai un ovverride della onDraw, poi prendi e quando succede qualcosa (in qualunque posto tu sia) setti il parametro del layer e forzi un redraw con postinvalidate.

 ;-)

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #9 il: 09 Aprile 2013, 23:31:33 CEST »
0
Se ti fai una imageview puoi andare a posizionare le cose dove ti pare con le dimensioni che preferisci.
Ti fai un ovverride della onDraw, poi prendi e quando succede qualcosa (in qualunque posto tu sia) setti il parametro del layer e forzi un redraw con postinvalidate.

 ;-)

Ok undead [nota per fan di d&d "libro rosso" : "prima che diventi un chierico e ti scacci"  8-)] credo mi serva aiuto su quello che hai scritto, hai esempi o tuts per capire dove devo infilarmi?

Giusto per spiegarmi meglio posto un'altra immagine per capirci, non è proprio quello che vorrei ottenere ma la logica è la stessa:


Praticamente una matrice x,y di stati 0-1 per definire quante luci in orizzontale e veritcale e quali accese e spente da piazzare su uno sfondo con appositi offset.
Se ti sono stato utile premi "Thanks" ;-)

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #10 il: 10 Aprile 2013, 10:50:45 CEST »
+1
E' più o meno come ha detto nanoandroide.

Prendi il tuo sfondo e lo dichiari nell'xml:

Codice (XML): [Seleziona]
 <tuopackage.TuaClasse
       android:id="@+id/LedBase"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:adjustViewBounds="true"
       android:src="@drawable/sfondo" />
Ovviamente per le view bounds e le dimensioni fai come ti resta più comodo dipende dal tuo layout.

Poi ti fai una classe nel tuopackage che si chiama TuaClasse e la derivi da imageview.
Quando vai a caricare nell'activity il layout prendi un puntatore a tuaclasse, così:

Codice (Java): [Seleziona]
TuaClasse sfondocustom = (TuaClasse) findViewById(R.id.LedBase);
In TuaClasse ti fai un metodo per settare il led corrente una roba tipo setLed(int i_nLed);

Ovviamente siccome hai un reference a quell'istanza (sfondocustom) tu puoi settare il led ovunque vuoi.. in un thread per esempio.
Ogni volta che cambi led fai così:

Codice (Java): [Seleziona]
sfondocustom.setLed(m_nCurrentLed);
sfondocustom.postInvalidate();

Il postinvalidate indica alla classe che deve effettuare un redraw, quindi nel caso della imageview (che è la classe base) ti ritrovi col metodo onDraw richiamato dal sistema.

Veniamo ora alla classe TuaClasse, derivata da imageview.
Poichè è derivata da imageview, la draw di default fa già quello che ti serve, cioè disegnare lo sfondo.
Prima disegni lo sfondo con la super.onDraw e poi disegni i tuoi elementi sopra.
Nel costruttore tu ti carichi la grafica del led (lo so che è brutto ma va beh) e poi passi a implementare la onDraw.

Codice (Java): [Seleziona]
@Override  
public void onDraw(Canvas canvas)
{    
super.onDraw(canvas); // fai disegnare PRIMA lo sfondo
if( m_nActiveLed == -1 ) // Se non hai ancora settato un led esci.
  return;
// A questo punto devi leggere il numero di led, convertirlo in coordinate corrette e disegnarlo..  E QUI INIZIA UN ALTRO PROBLEMA****
}

***
Qua c'è da fare un discorso, che è in parte quello che stavo dicendo in questa sezione in un thread sul posizionamento di elementi complessi al pixel.

Tu hai uno sfondo di 1000x1000 ma non sai esattamente quanto sarà grossa sul device di turno. Tralascio problemi di aspect ratio che sono trascurabili nel contesto.

Tu devi ragionare in pixel lascia perdere tutte le stupidaggini di designing for multiple resolutions.
Ti faccio l'esempio per una riga poi te lo aggiusti per quello che ti serve (una matrice).
Tu hai una immagine larga 1000 che ha 5 posizioni per i led. Hai 100 pixel di margine dx e 100 pixel di margine sx.
Le posizioni (riferimento angolo in alto a sx) sono dunque: 100 300 500 700 900

Quindi converti queste posizioni in rapporti, ovvero:
inizi al 10% della dimensione totale (0.1).
Ogni passo è uguale al 20% (0.2).
L'algoritmo sarà quindi (con nLed che parte da 0): x = (0.1f+nLed*0.2f)*dimensioneimmagine.

Tu devi ricavare due cose nella ondraw:
1- la dimensione effettiva della bitmap che stai disegnando
2- il rapporto tra quello che vedi su schermo e l'immagine originale

Passo uno è semplice puoi prendere la larghezza della view (se hai fillato). Mettiamo sia 800.
L'algoritmo per il posizionamento funziona e ti calcoli la posizione relativa con

x = (0.1f+nLed*0.2f)*800.

Ovvero le posizioni sono:

80 240 400 560 720

Il margine dx e sx è quindi 80 pixel che sono esattamente il 10% così come ci si aspetterebbe.

Quando tu vai a disegnare la bitmap però ti serve sapere la scala, cioè di quanto si è rimpicciolito (o ingrandito) lo sfondo.
Calcoli quindi 800/1000 (cioè dimensionereale/dimensioneoriginale) = 0.8.
Se le immagini dei tuoi led sono larghe in origine 200 pixel queste devono diventare 160, per fare questo disegni la bitmap applicando una scala con una matrice (c'è una funzione apposita).

In pratica alla fine ti ritrovi con:
Codice (Java): [Seleziona]
x = (0.1f+(nLed%5)*0.2f)*nuovadimensioneX.
y = (0.1f+(nLed/5)*0.2f)*nuovadimensioneY.
// Fai una matrice di scala che scala per scalaX e scalaY e trasla alla posizione.
// Così su due piedi non mi ricordo l'ordine se non funziona inverti traslazione e scala.
Matrix matrix = new Matrix();
matrix.postTranslation(x,y);
matrix.postScale(nuovaDimensioneX/dimensioneOriginaleX,nuovaDimensioneY/dimensioneOriginaleY);
canvas.drawBitmap(led,matrix,null);

Se il metodo fa quello che ti serve hai ottenuto:
1- risparmio di memoria perchè non fai cose allucinanti, hai 1 sfondo ed 1 led.
2- indipendentemente dalla risoluzione del device tu mantieni le proporzioni relative degli elementi quindi sei SICURO che se hai nello sfondo un led spento il tuo led acceso ci andrà sopra senza alcun problema
3- decidi tu quando disegnare perchè fai un trigger dell'evento col postInvalidate, quindi il metodo funziona coi thread
4- se vuoi costruire un elemento complesso ti basta prendere un qualsiasi programma di disegno, piazzarci lo sfondo e poi attaccare elementi sopra scrivendoti da una parte le posizioni relative. in questo modo puoi costruire qualsiasi cosa.

Questo è quello a cui mi riferivo nel thread sugli elementi complessi, cioè questo è quello che secondo me andrebbe fatto quando si ha a che fare con elementi complessi che devono avere delle posizioni relative precise al pixel (se il led è pochi pixel fuori viene brutto perchè vedi che lo sfondo non corrisponde).

Il tutto come questione di principio, indipendentemente dal fatto che tu usi una surfaceview, una imageview custom o passi ad opengl.

 ;-)

EDIT: aggiungo un'altra cosa, per completezza d'informazione.
Questo sistema non ti impedisce comunque (sempre che tu non stia usando opengl) di adottare delle pratiche comuni e di buon senso per gestire tipi differenti di device. La tua immagine 1000x1000 può essere ridimensionata manualmente a 500x500 o 400x400 o quello che vuoi per device con schermi più piccoli. Lo stesso vale per il led. Puoi comunque creare un set di immagini per gestire più device a patto che ovviamente tu scali tutto con le medesime proporzioni.

Sulla base di quanto ho scritto potresti anche decidere alcune variazioni sul tema, tipo:
- setti manualmente lo sfondo con setImageBitmap così le dimensioni originali te le prendi dalla bitmap che ha scelto il sistema (a seconda della risoluzione del device)
- scali il led quando carichi la bitmap in modo da evitare di portarti dietro la matrice
« Ultima modifica: 10 Aprile 2013, 11:00:52 CEST da undead »

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #11 il: 10 Aprile 2013, 14:47:55 CEST »
0
Grazie molte a tutti per l'interessamento!

E' più o meno come ha detto nanoandroide.

Prendi il tuo sfondo e lo dichiari nell'xml:

Codice (XML): [Seleziona]
 <tuopackage.TuaClasse

Come mai nell'xml inserisci questo?


Poi ti fai una classe nel tuopackage che si chiama TuaClasse e la derivi da imageview.

Ok

Quando vai a caricare nell'activity il layout prendi un puntatore a tuaclasse, così:

Codice (Java): [Seleziona]
TuaClasse sfondocustom = (TuaClasse) findViewById(R.id.LedBase);

Ok

In TuaClasse ti fai un metodo per settare il led corrente una roba tipo setLed(int i_nLed);

Ovviamente siccome hai un reference a quell'istanza (sfondocustom) tu puoi settare il led ovunque vuoi.. in un thread per esempio.

Non ho capito esattamente cosa dovrebbe fare il metodo, restituire un drawable o bitmap e le coordinate ad esempio?

Ogni volta che cambi led fai così:

Codice (Java): [Seleziona]
sfondocustom.setLed(m_nCurrentLed);
sfondocustom.postInvalidate();

Il postinvalidate indica alla classe che deve effettuare un redraw, quindi nel caso della imageview (che è la classe base) ti ritrovi col metodo onDraw richiamato dal sistema.

Ok

Veniamo ora alla classe TuaClasse, derivata da imageview.
Poichè è derivata da imageview, la draw di default fa già quello che ti serve, cioè disegnare lo sfondo.

Ok

Prima disegni lo sfondo con la super.onDraw e poi disegni i tuoi elementi sopra.
Nel costruttore tu ti carichi la grafica del led (lo so che è brutto ma va beh) e poi passi a implementare la onDraw.

Codice (Java): [Seleziona]
@Override  
public void onDraw(Canvas canvas)
{    
super.onDraw(canvas); // fai disegnare PRIMA lo sfondo
if( m_nActiveLed == -1 ) // Se non hai ancora settato un led esci.
  return;
// A questo punto devi leggere il numero di led, convertirlo in coordinate corrette e disegnarlo..  E QUI INIZIA UN ALTRO PROBLEMA****
}

Non ho capito bene cosa intendi dire "nel costruttore ti carichi la grafica del led"  ???
AGGIORNAMENTO: In questo caso però ridisegnerei lo sfondo tutte le volte giusto?


***
Qua c'è da fare un discorso, che è in parte quello che stavo dicendo in questa sezione in un thread sul posizionamento di elementi complessi al pixel.

Tu hai uno sfondo di 1000x1000 ma non sai esattamente quanto sarà grossa sul device di turno. Tralascio problemi di aspect ratio che sono trascurabili nel contesto.

Tu devi ragionare in pixel lascia perdere tutte le stupidaggini di designing for multiple resolutions.
Ti faccio l'esempio per una riga poi te lo aggiusti per quello che ti serve (una matrice).
Tu hai una immagine larga 1000 che ha 5 posizioni per i led. Hai 100 pixel di margine dx e 100 pixel di margine sx.
Le posizioni (riferimento angolo in alto a sx) sono dunque: 100 300 500 700 900

Quindi converti queste posizioni in rapporti, ovvero:
inizi al 10% della dimensione totale (0.1).
Ogni passo è uguale al 20% (0.2).
L'algoritmo sarà quindi (con nLed che parte da 0): x = (0.1f+nLed*0.2f)*dimensioneimmagine.

Tu devi ricavare due cose nella ondraw:
1- la dimensione effettiva della bitmap che stai disegnando
2- il rapporto tra quello che vedi su schermo e l'immagine originale

Passo uno è semplice puoi prendere la larghezza della view (se hai fillato). Mettiamo sia 800.
L'algoritmo per il posizionamento funziona e ti calcoli la posizione relativa con

x = (0.1f+nLed*0.2f)*800.

Ovvero le posizioni sono:

80 240 400 560 720

Il margine dx e sx è quindi 80 pixel che sono esattamente il 10% così come ci si aspetterebbe.

Quando tu vai a disegnare la bitmap però ti serve sapere la scala, cioè di quanto si è rimpicciolito (o ingrandito) lo sfondo.
Calcoli quindi 800/1000 (cioè dimensionereale/dimensioneoriginale) = 0.8.
Se le immagini dei tuoi led sono larghe in origine 200 pixel queste devono diventare 160, per fare questo disegni la bitmap applicando una scala con una matrice (c'è una funzione apposita).

In pratica alla fine ti ritrovi con:
Codice (Java): [Seleziona]
x = (0.1f+(nLed%5)*0.2f)*nuovadimensioneX.
y = (0.1f+(nLed/5)*0.2f)*nuovadimensioneY.
// Fai una matrice di scala che scala per scalaX e scalaY e trasla alla posizione.
// Così su due piedi non mi ricordo l'ordine se non funziona inverti traslazione e scala.
Matrix matrix = new Matrix();
matrix.postTranslation(x,y);
matrix.postScale(nuovaDimensioneX/dimensioneOriginaleX,nuovaDimensioneY/dimensioneOriginaleY);
canvas.drawBitmap(led,matrix,null);

Trasposizione matriciale a parte, il concetto è abbastanza chiaro anche se non saprei dove inserire questa parte di codice se non nel thread che scorre tutte le posizioni e colloca i led.

Se il metodo fa quello che ti serve hai ottenuto:
1- risparmio di memoria perchè non fai cose allucinanti, hai 1 sfondo ed 1 led.
2- indipendentemente dalla risoluzione del device tu mantieni le proporzioni relative degli elementi quindi sei SICURO che se hai nello sfondo un led spento il tuo led acceso ci andrà sopra senza alcun problema
3- decidi tu quando disegnare perchè fai un trigger dell'evento col postInvalidate, quindi il metodo funziona coi thread
4- se vuoi costruire un elemento complesso ti basta prendere un qualsiasi programma di disegno, piazzarci lo sfondo e poi attaccare elementi sopra scrivendoti da una parte le posizioni relative. in questo modo puoi costruire qualsiasi cosa.

Questo è quello a cui mi riferivo nel thread sugli elementi complessi, cioè questo è quello che secondo me andrebbe fatto quando si ha a che fare con elementi complessi che devono avere delle posizioni relative precise al pixel (se il led è pochi pixel fuori viene brutto perchè vedi che lo sfondo non corrisponde).

Il tutto come questione di principio, indipendentemente dal fatto che tu usi una surfaceview, una imageview custom o passi ad opengl.

Ottimo!

EDIT: aggiungo un'altra cosa, per completezza d'informazione.
Questo sistema non ti impedisce comunque (sempre che tu non stia usando opengl) di adottare delle pratiche comuni e di buon senso per gestire tipi differenti di device. La tua immagine 1000x1000 può essere ridimensionata manualmente a 500x500 o 400x400 o quello che vuoi per device con schermi più piccoli. Lo stesso vale per il led. Puoi comunque creare un set di immagini per gestire più device a patto che ovviamente tu scali tutto con le medesime proporzioni.

Immagino tu intenda dire che è meglio evitare di far fare al sistema l'autoscaling, per una resa visiva migliore, giusto?

Sulla base di quanto ho scritto potresti anche decidere alcune variazioni sul tema, tipo:
- setti manualmente lo sfondo con setImageBitmap così le dimensioni originali te le prendi dalla bitmap che ha scelto il sistema (a seconda della risoluzione del device)
- scali il led quando carichi la bitmap in modo da evitare di portarti dietro la matrice

Mhhh questa forse mi sembra ancora più semplice ...

Ad ogni modo sto provando a fare un progetto pilota con quanto mi avete scritto.
Cosa ne dite se lo aggiungo al primo post così potrete darmi qualche delucidazione in più dove avessi lacune?  O:-)

Grazie ancora
« Ultima modifica: 10 Aprile 2013, 15:57:47 CEST da Eu4ia »
Se ti sono stato utile premi "Thanks" ;-)

Offline undead

  • Utente senior
  • ****
  • Post: 666
  • Respect: +113
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S6
  • Play Store ID:
    DrKappa
  • Sistema operativo:
    Windows 10 64-bit, Windows 8.1 64-bit
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #12 il: 10 Aprile 2013, 17:13:14 CEST »
0
Come mai nell'xml inserisci questo?
Lo insrerisco per fargli caricare la classe custom direttamente. Altrimenti dovrei creare una istanza di TuaClasse e andarmela ad aggiungere a mano, invece così fa tutto lui e io devo solo prendere l'istanza con la FindViewById.
Citazione
Non ho capito esattamente cosa dovrebbe fare il metodo, restituire un drawable o bitmap e le coordinate ad esempio?
Il metodo dovrebbe solo settare un intero che ti dice quale led è acceso.  ;-)
Puoi anche dichiarare l'intero public.

Citazione
Non ho capito bene cosa intendi dire "nel costruttore ti carichi la grafica del led"  ???
AGGIORNAMENTO: In questo caso però ridisegnerei lo sfondo tutte le volte giusto?
No no, intendo dire che tu hai due files:
sfondo.png - lo sfondo del "semaforo spento" che setti nel layout xml così viene caricato automaticamente.
led.png - una singola luce staccata dal resto

Nel costruttore della tua imageview custom puoi caricare il led come qualsiasi bitmap.
Oppure ancora meglio ti fai una funzione init dentro TuaClasse che carica il led e la chiami subito dopo aver preso l'istanza con findViewById.

Citazione
Trasposizione matriciale a parte, il concetto è abbastanza chiaro anche se non saprei dove inserire questa parte di codice se non nel thread che scorre tutte le posizioni e colloca i led.
Questo codice lo metti nella ondraw dopo che hai chiamato la super e dopo che hai verificato che nled != -1.
Il concetto è proprio quello di separare l'update dal disegno.

Nel tuo thread setti il numero led al valore che vuoi.
Poi sempre nel thread lanci un postInvalidate per dire alla tua imageview che deve ridisegnarsi.
...
...
...
In un tempo X nel futuro verrà chiamata la onDraw della tua imageview che poi andrà (con questa parte di codice) a verificare quale led è accesso e deciderà dove posizionarlo.
Citazione
Immagino tu intenda dire che è meglio evitare di far fare al sistema l'autoscaling, per una resa visiva migliore, giusto?
In generale il problema è che una bitmap da 1000x1000 sono 1 milione di pixel il che equivale in ARGB8888 a 4mb. Se il mio device ha lo schermo mini è facile che anche la cpu e la memoria siano mini!

A quel punto non solo entra in gioco il fatto che da un programma di disegno la resa viene meglio rispetto a una scalatura in tempo reale, hai anche il problema che il numero di pixel aumenta e il tutto va più lento. Per intenderci una immagine 500x500 ha 4 volte meno pixel (4 volte meno lavoro per l'hw) e occupa 4 volte meno memoria rispetto a una 1000x1000.

 ;-)
« Ultima modifica: 10 Aprile 2013, 18:29:28 CEST da undead »

Offline Eu4ia

  • Utente junior
  • **
  • Post: 93
  • Respect: +16
    • Mostra profilo
  • Play Store ID:
    Eu4ia
  • Sistema operativo:
    Ubuntu 11.10 + Windows 7
Re:ImageView con sovrapposizione di drawables o bitmap
« Risposta #13 il: 12 Aprile 2013, 17:17:56 CEST »
0
Ok chiudo come RISOLTO visto l'ottimo tutorial scritto da undead reperibile qui:
http://www.anddev.it/index.php/topic,10730.0.html

Complimenti!  8-)
Se ti sono stato utile premi "Thanks" ;-)