2012-01-06 10 views
19

Ho un LinearLayout che vorrei cambiare il colore di sfondo di quando si fa clic su una delle sue viste secondarie (un ImageButton). Sono in grado di farlo, ma non immediatamente - il cambiamento non si verifica sullo schermo fino a più tardi (penso durante una chiamata onResume). Mi piacerebbe scoprire come forzare il layout a ridisegnare dopo aver impostato lo sfondo, prima che venga eseguita la prossima riga di codice. Ecco il metodo onClick del mio OnClickListener per il pulsante:Come forzare una vista per ridisegnare immediatamente prima dell'esecuzione della riga successiva del codice

di comando
public void onClick(View v) { 

    LinearLayout parentLayout = (LinearLayout) v.getParent(); 
    parentLayout.setBackgroundResource(R.color.my_color); 
    SystemClock.sleep(1000); //ms 

} 

Il sonno è lì per verificare se il ridisegno accade prima o dopo di esso. Il risultato: dopo. La maggior parte delle domande su questo argomento (come here e here) dicono di usare invalidate() sulla vista. Ho usato i comandi parentLayout.invalidate();, parentLayout.postInvalidate(); e parentLayout.refreshDrawableState(); tra lo sfondo e le linee di sospensione, tutto inutilmente. Il ridisegno si verifica ancora dopo il comando di sospensione. Qualcuno può dirmi come farlo accadere immediatamente?

Altre informazioni utili: LinearLayout è associato alle righe di un ListView e OnClickListener in precedenza si trova in una classe personalizzata che estende SimpleCursorAdapter, non nell'attività stessa. (In questo modo posso impostare un listener per ciascuna delle righe in ListView.)

+0

Sembra che non otterrete la risposta esatta per questo almeno non potrei trovarne uno. Puoi dirci perché hai bisogno che la vista venga ridisegnata immediatamente? Forse ci saranno altre soluzioni per risolvere il problema. – manjusg

+0

@manjusg Quello che sto cercando di fare è proprio quello che viene normalmente fatto con il selettore in background di una vista in xml (lo sfondo cambia brevemente colore quando premuto poco prima dell'esecuzione della sua richiamata), tranne che voglio cambiare lo sfondo di una vista diversa da il pulsante premuto - vale a dire il layout che contiene il pulsante e anche una vista testuale. – pvans

+0

@manjusg Le righe del mio listview hanno un testo e un pulsante di cancellazione, e vorrei che l'intera riga, inclusa la textview, fosse brevemente evidenziata prima di essere cancellata e rimossa, in modo che l'utente abbia qualche feedback che ha premuto il fila voleva dire. Forse c'è un modo per collegare le viste dei collegamenti con un selettore in xml? – pvans

risposta

2

Ok, ho finalmente trovato una soluzione a questo problema ed è semplice. Sembra che il problema fosse solo che stavo eseguendo le modifiche estraibili in un OnClickLIstener, quando avrei dovuto farlo in un OnTouchListener. Se imposto un OnTouchListener per il mio pulsante che cerca ACTION_DOWN e quindi esegue setBackgroundColor sul suo layout padre, la modifica avviene immediatamente.

Una soluzione alternativa meno robusta proviene da this post. È possibile assegnare un selettore per lo sfondo del layout principale in xml, quindi in OnTouchListener menzionato sopra, eseguire setPressed (true) su tale layout. Non è una soluzione eccezionale perché il selettore ti offre molta meno libertà rispetto alla modifica diretta delle proprietà della vista nel codice. Ad esempio, non è possibile impostare lo sfondo del layout su un colore diverso premendo un pulsante diverso.

Grazie a coloro che hanno contribuito con suggerimenti su questo!

1

apportare le modifiche e chiamare listview.invalidate(); per riflettere tali cambiamenti sull'interfaccia utente

+0

Non ho accesso diretto a ListView stesso in questo codice, poiché si trova nella classe dell'adattatore, non nell'attività. Sono in grado di fare riferimento aListView utilizzando questa riga: 'mActivity.mListView.invalidate();' (mActivity è l'attività di chiamata estratta dal contesto, mListView è un campo pubblico dell'attività che fa riferimento a ListView), ma l'inserimento di questa riga prima del dormire non risolve il problema. – pvans

3

Si potrebbe provare forceLayout() con una chiamata a draw(canvas) subito dopo. Se non hai eseguito l'override di onLayout(), onMeasure, draw() o onDraw(), verrà eseguita l'implementazione predefinita. L'unico problema con questo è che devi ottenere la tela o crearne una manualmente.

È fortemente sconsigliato perseguire questo approccio poiché Android è progettato specificamente per evitare di disegnare al di fuori dei normali aggiornamenti. Mentre sei corretto che invalidate() non si verifica immediatamente, è il modo più sicuro e migliore per incoraggiare un ridisegno. Se vuoi gestire il disegno al di fuori degli aggiornamenti, Android offre un modo per farlo con la classe SurfaceHolder.

+0

Hmm. Penso che preferirei evitare pratiche fortemente scoraggiate. Sto aggiungendo qualche informazione in più su ciò che sto cercando di ottenere come commento nella domanda. – pvans

+0

Detto questo, c'è qualcosa da considerare: le linee guida di Android incoraggiano fortemente a non bloccare mai il thread dell'interfaccia utente per un motivo. Inserendo il comando 'SystemClock.sleep()', stai bloccando il thread dell'interfaccia utente. Se questo è per test di teoria, fantastico! Per favore fateci sapere le vostre scoperte. Se questo è per un'applicazione del mondo reale, vorrei fortemente rianalizzare il tuo programma. –

+0

Il sonno è solo per test. Per curiosità, come consiglieresti di implementare una pausa, ad esempio, tra un clic e l'azione di callback associata? – pvans

Problemi correlati