Trovo che lo stile riguardi lo sherlocking attraverso la struttura. Il quello che (quasi sempre) deriva dall'implementazione del widget. Il dove, trovo è dappertutto. Farò del mio meglio per spiegare il processo attraverso il tuo caso d'uso particolare: i pulsanti di AlertDialog.
Partendo:
Hai già capito questo: si parte con il codice sorgente del widget. Stiamo cercando in particolare di trovare - dove i pulsanti AlertDialog ottengono il loro colore del testo. Quindi, iniziamo guardando da dove provengono questi pulsanti. Sono stati creati esplicitamente in fase di runtime? O sono definiti in un layout xml, che viene gonfiato?
Nel codice sorgente, troviamo che mAlert
gestisce le opzioni dei pulsanti tra le altre cose:
public void setButton(int whichButton, CharSequence text, Message msg) {
mAlert.setButton(whichButton, text, null, msg);
}
mAlert
è un'istanza di AlertController
. Nel suo costruttore, troviamo che l'attributo alertDialogStyle
definisce il layout xml:
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.AlertDialog,
com.android.internal.R.attr.alertDialogStyle, 0);
mAlertDialogLayout =
a.getResourceId(
com.android.internal.R.styleable.AlertDialog_layout,
com.android.internal.R.layout.alert_dialog);
Così, il layout dovremmo guardare è alert_dialog.xml
-[sdk_folder]/platforms/android-21/data/res/layout/alert_dialog.xml
:
Il layout XML è piuttosto lungo. Questa è la parte rilevante:
<LinearLayout>
....
....
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
android:orientation="vertical" >
<LinearLayout
style="?android:attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dip"
android:paddingStart="2dip"
android:paddingEnd="2dip"
android:measureWithLargestChild="true">
<LinearLayout android:id="@+id/leftSpacer"
android:layout_weight="0.25"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
<Button android:id="@+id/button1"
android:layout_width="0dip"
android:layout_gravity="start"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="end"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:maxLines="2"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
android:layout_width="0dip"
android:layout_weight="0.25"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
</LinearLayout>
Ora sappiamo che i pulsanti ottenere lo stile tenuto da attributo buttonBarButtonStyle
.
oltre al capo [sdk_folder]/platforms/android-21/data/res/values/themes.material.xml
e cercare buttonBarButtonStyle
:
<!-- Defined under `<style name="Theme.Material">` -->
<item name="buttonBarButtonStyle">@style/Widget.Material.Button.ButtonBar.AlertDialog</item>
<!-- Defined under `<style name="Theme.Material.Light">` -->
<item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
A seconda di quale tema genitore la vostra attività è, buttonBarButtonStyle
farà riferimento a uno di questi due stili. Per ora, supponiamo che il tema della tua attività si estenda su Theme.Material
.Vedremo @style/Widget.Material.Button.ButtonBar.AlertDialog
:
Aprire [sdk_folder]/platforms/android-21/data/res/values/styles_material.xml
e cercare Widget.Material.Button.ButtonBar.AlertDialog
:
<!-- Alert dialog button bar button -->
<style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored">
<item name="minWidth">64dp</item>
<item name="maxLines">2</item>
<item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
Va bene. Ma questi valori non ci aiutano a determinare il colore del testo del pulsante. Dovremmo guardare lo stile principale successivo - Widget.Material.Button.Borderless.Colored
:
<!-- Colored borderless ink button -->
<style name="Widget.Material.Button.Borderless.Colored">
<item name="textColor">?attr/colorAccent</item>
<item name="stateListAnimator">@anim/disabled_anim_material</item>
</style>
Infine, troviamo il textColor
- e la sua forniti da attr/colorAccent
inizializzate in Theme.Material
:
<item name="colorAccent">@color/accent_material_dark</item>
Per Theme.Material.Light
, colorAccent
è definito come:
<item name="colorAccent">@color/accent_material_light</item>
Vai a [sdk_folder]/platforms/android-21/data/res/values/colors_material.xml
e individuare th colori ESE:
<color name="accent_material_dark">@color/material_deep_teal_200</color>
<color name="accent_material_light">@color/material_deep_teal_500</color>
<color name="material_deep_teal_200">#ff80cbc4</color>
<color name="material_deep_teal_500">#ff009688</color>
Schermata di un AlertDialog e il corrispondente del testo-color:

rapida:
A volte, è più facile da leggere il valore del colore (come in l'immagine sopra) e cercarla usando AndroidXRef. Questo approccio non sarebbe stato utile nel tuo caso dal #80cbc4
avrebbe solo sottolineato che è il colore dell'accento. Dovresti comunque individuare Widget.Material.Button.Borderless.Colored
e legarlo con l'attributo buttonBarButtonStyle
.
Modifica del pulsante di testo-colore:
Idealmente, dovremmo creare uno stile che si estende Widget.Material.Button.ButtonBar.AlertDialog
, ignorare android:textColor
al suo interno, e assegnarlo ad attribuire buttonBarButtonStyle
. Ma questo non funzionerà - il tuo progetto non verrà compilato. Questo perché Widget.Material.Button.ButtonBar.AlertDialog
è uno stile non pubblico e, quindi, non può essere esteso. Puoi confermarlo selezionando Link.
Faremo la cosa migliore: estendere lo stile principale di Widget.Material.Button.ButtonBar.AlertDialog
- Widget.Material.Button.Borderless.Colored
che è pubblico.
<style name="CusButtonBarButtonStyle"
parent="@android:style/Widget.Material.Button.Borderless.Colored">
<!-- Yellow -->
<item name="android:textColor">#ffffff00</item>
<!-- From Widget.Material.Button.ButtonBar.AlertDialog -->
<item name="android:minWidth">64dp</item>
<item name="android:maxLines">2</item>
<item name="android:minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
Si noti che aggiungiamo altri 3 elementi dopo aver annullato android:textColor
. Questi sono di tipo non pubblico Widget.Material.Button.ButtonBar.AlertDialog
. Dal momento che non possiamo estenderlo direttamente, dobbiamo includere gli elementi che definisce. Nota: il valore dimen deve essere esaminato e trasferito nei file appropriati res/values(-xxxxx)/dimens.xml
nel progetto.
Lo stile CusButtonBarButtonStyle
verrà assegnato all'attributo buttonBarButtonStyle
. Ma la domanda è: come farà a sapere un AlertDialog?Dal codice sorgente:
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
Passando 0
come secondo argomento per resolveDialogTheme(Context, int)
finirà nella clausola else
:
static int resolveDialogTheme(Context context, int resid) {
if (resid == THEME_TRADITIONAL) {
....
} else {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(
com.android.internal.R.attr.alertDialogTheme,
outValue, true);
return outValue.resourceId;
}
}
Ora sappiamo che il tema è detenuto da attributo alertDialogTheme
. Successivamente, guardiamo a ciò che indica alertDialogTheme
. Il valore di questo attributo dipenderà dal tema principale della tua attività. Passare alla cartella sdk e trovare il values/themes_material.xml
all'interno di Android-21. Cerca alertDialogTheme
. Risultati:
<!-- Defined under `<style name="Theme.Material">` -->
<item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>
<!-- Defined under `<style name="Theme.Material.Light">` -->
<item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>
<!-- Defined under `<style name="Theme.Material.Settings">` -->
<item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
Quindi, sulla base di ciò tema di base della vostra attività è, alertDialogTheme
terrà uno di questi 3 valori. Per far sapere ad AlertDialog di CusButtonBarButtonStyle
, dobbiamo sostituire l'attributo alertDialogTheme
nel tema della nostra app. Supponiamo che stiamo usando Theme.Material
come tema di base.
<style name="AppTheme" parent="android:Theme.Material">
<item name="android:alertDialogTheme">@style/CusAlertDialogTheme</item>
</style>
Dall'alto, sappiamo che alertDialogTheme
punti per Theme.Material.Dialog.Alert
quando tema di base della tua app è Theme.Material
. Così, CusAlertDialogTheme
dovrebbe avere Theme.Material.Dialog.Alert
come suo genitore:
<style name="CusAlertDialogTheme"
parent="android:Theme.Material.Dialog.Alert">
<item name="android:buttonBarButtonStyle">@style/CusButtonBarButtonStyle</item>
</style>
Risultato:

Così, invece di accettare pesce da mangiare, mi puoi insegnare a pescare invece?
Per lo meno, spero di aver spiegato dove sono i pesci.
P.S. Mi rendo conto di aver postato un mammut.
WOW, solo WOW. È il casino che ho immaginato che fosse. Google ha ancora bisogno di imparare molto sullo sviluppo dell'API :(Almeno Materiale cerca di risolvere questi problemi Ora, per vedere se riesco a tradurre quello che ho imparato qui sul tema Appcompat che sto usando attualmente. – velis
@velis lol, quindi vero. Fatemi sapere se siete stati in grado di utilizzare questo approccio nella personalizzazione del tema Appcompat.Se colpisci un muro, possiamo discutere ulteriormente. A proposito, ottima domanda, e grazie per la generosità. – Vikram
su android-24 il file dei temi è themes_material.xml – dazza5000