Android: modifica la visualizzazione del titolo personalizzata in fase di esecuzione

StackOverflow https://stackoverflow.com/questions/820398

  •  03-07-2019
  •  | 
  •  

Domanda

Sto usando una vista del titolo personalizzata nella mia applicazione per ogni attività. In una delle attività, in base ai clic sui pulsanti, devo modificare la vista del titolo personalizzata. Ora funziona perfettamente ogni volta che faccio una chiamata a setFeatureInt.

Ma se provo ad aggiornare qualsiasi elemento nel titolo personalizzato (diciamo cambiare il testo di un pulsante o una vista di testo sul titolo), l'aggiornamento non ha luogo.

Il debug tramite il codice mostra che la visualizzazione del testo e le istanze dei pulsanti non sono nulle e posso anche vedere la barra del titolo personalizzata. Ma il testo nella vista testo o nel pulsante non viene aggiornato. Qualcun altro ha affrontato questo problema? Come lo risolvo?

Grazie.

Modifica

Ecco cosa ho provato. Non viene aggiornato nemmeno quando si chiama postInvalidate.

    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.text_title);

    TextView databar = (TextView) findViewById(R.id.title_text);
    databar.setText("Some Text");
    databar.postInvalidate();

    Button leftButton = (Button) findViewById(R.id.left_btn);
    leftButton.setOnClickListener(mLeftListener);
    leftButton.setText("Left Btn");
    leftButton.postInvalidate();

    Button rightBtn = (Button) findViewById(R.id.right_btn);
    rightBtn.setOnClickListener(mRightListener);
    rightBtn.postInvalidate();
È stato utile?

Soluzione

Il problema è che l'unico Window implementazione ( PhoneWindow ) utilizza un LayoutInflater nel suo metodo setFeatureInt e crea un'istanza del nuovo layout con infllate e attachToRoot = true . Di conseguenza, quando si chiama setFeatureInt , i nuovi layout non vengono sostituiti ma collegati al contenitore del titolo interno e quindi disegnati uno sopra l'altro.

Puoi aggirare il problema utilizzando il seguente metodo di supporto anziché setFeatureInt . L'helper rimuove semplicemente tutte le viste dal contenitore del titolo interno prima di impostare la nuova funzione di titolo personalizzato:


private void setCustomTitleFeatureInt(int value) {
    try {
        // retrieve value for com.android.internal.R.id.title_container(=0x1020149)
        int titleContainerId = (Integer) Class.forName(
            "com.android.internal.R$id").getField("title_container").get(null);

        // remove all views from titleContainer
        ((ViewGroup) getWindow().findViewById(titleContainerId)).removeAllViews();

        // add new custom title view 
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, value);

    } catch(Exception ex) {
        // whatever you want to do here..
    }
}

Non sono sicuro che sia previsto l'attuale comportamento setFeatureInt , ma non è certamente documentato in un modo o nell'altro, motivo per cui lo porterò agli sviluppatori Android;)

Modifica

Come sottolineato nei commenti, la soluzione sopra menzionata non è l'ideale. Invece di fare affidamento sulla costante com.android.internal.R.id.title_container potresti semplicemente nascondere il vecchio titolo personalizzato ogni volta che ne imposti uno nuovo.

Supponiamo che tu abbia due layout di titolo personalizzati:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/custom_title_1" ...

e

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/custom_title_2" ...

e vuoi sostituire custom_title_1 con custom_title_2 , potresti nascondere il primo e usare setFeatureInt per aggiungere il secondo:

findViewById(R.id.custom_title_1).setVisibility(View.GONE);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_2);

Altri suggerimenti

Il modo corretto per farlo è il seguente:

requestWindowFeature( Window.FEATURE_CUSTOM_TITLE );
setContentView( R.layout.my_layout );
getWindow().setFeatureInt( Window.FEATURE_CUSTOM_TITLE, R.layout.my_custom_title );
super.onCreate( savedInstanceState );

Si noti che l'ordine di queste dichiarazioni è molto importante.

Se chiami super.onCreate () prima di una qualsiasi delle altre istruzioni otterrai una barra del titolo vuota, che verrà risolta dall'hacking di trovare l'id della barra del titolo e rimuovere tutte le viste da essa, ma non è raccomandato.

Stai chiamando invalidate o postInvalidate per ridisegnare la vista dopo aver aggiornato il testo? Se è una vista personalizzata, puoi inserire un punto di interruzione nel codice di disegno per assicurarti che venga chiamato?

Se sei nel thread dell'interfaccia utente, puoi chiamare 'invalidate' se non lo sei, devi chiamare 'postInvalidate' altrimenti la vista non si ridisegna da sola.

Solo il mio valore 2c:

Quando si lavora in MapActivity, la richiesta di un titolo personalizzato non ha mostrato alcun titolo.

Fortunatamente, tutto quello che volevo fare era impostare il testo del titolo in modo diverso, e presto mi resi conto che solo chiamare setTitle () all'interno di onCreate () funzionava per me (l'ho chiamato dopo aver chiamato setContentView ())

Scusa, ma non ho più tempo per eseguire il debug di questo e capire perché ciò che stavo facendo non ha funzionato e perché cambiarlo lo ha fatto funzionare. Come ho detto, ho pensato che questo potesse aiutare qualcuno in fondo alla strada.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top