Jak odkrywać styl w Androidzie
[2]} próbuję motywować moją aplikację na Androida. Jednak każdy widget jest potwornym bólem samym w sobie: muszę szukać motywów tego konkretnego widgetu, a następnie stworzyć styl, który miejmy nadzieję wywodzi się z tego samego stylu, którego używa widget.
Oczywiście odpowiedzi na temat konkretnego widżetu nie zawsze zawierają informacje o stylu bazowym, tylko konkretne kolory.
Więc zamiast akceptować ryby do jedzenia, czy możesz nauczyć mnie łowić?Jak interpretować te ObtainStyledAttributes()
wywołania w konstruktorach widżetów i wyodrębnić style z tego? Jak to odtworzyć?
2 answers
Uważam, że stylizacja jest o sherlocking drogę przez ramy. co (prawie zawsze) pochodzi z implementacji widgetu. gdzie , znajduję jest wszędzie. Postaram się jak najlepiej wyjaśnić proces za pomocą Twojego konkretnego przypadku użycia-przycisku(y) AlertDialog.
Początek :
Już to rozgryzłeś: zaczynamy od kodu źródłowego widgetu. W szczególności staramy się znaleźć-gdzie AlertDialog przyciski mają swój kolor tekstu. Zacznijmy więc od tego, skąd pochodzą te przyciski. Czy są one jawnie tworzone w czasie wykonywania? Czy są one zdefiniowane w układzie xml, który jest zawyżany?
W kodzie źródłowym znajdujemy, że mAlert
obsługuje między innymi opcje przycisków:
public void setButton(int whichButton, CharSequence text, Message msg) {
mAlert.setButton(whichButton, text, null, msg);
}
mAlert
jest instancją AlertController
. W jego konstruktorze stwierdzamy, że atrybut alertDialogStyle
definiuje układ 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);
Więc układ, na który powinniśmy spojrzeć to alert_dialog.xml
- [sdk_folder]/platforms/android-21/data/res/layout/alert_dialog.xml
:
Układ XML jest dość długi. Jest to odpowiednia część:
<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>
Wiemy teraz, że przyciski otrzymują styl trzymany przez atrybut buttonBarButtonStyle
.
Udaj się do [sdk_folder]/platforms/android-21/data/res/values/themes.material.xml
i Szukaj 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>
W zależności od motywu nadrzędnego Twojej aktywności, buttonBarButtonStyle
będzie odnosił się do jednego z tych dwóch stylów. Na razie Załóżmy, że temat Twojej aktywności rozszerza Theme.Material
. Przyjrzymy się @style/Widget.Material.Button.ButtonBar.AlertDialog
:
Otwórz [sdk_folder]/platforms/android-21/data/res/values/styles_material.xml
i wyszukaj 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>
Ok. Ale te wartości nie pomagają nam w określeniu koloru tekstu przycisku. Powinniśmy przyjrzeć się stylowi rodzica - 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>
W końcu znajdujemy textColor
- i jego dostarczone przez attr/colorAccent
zainicjalizowane w Theme.Material
:
<item name="colorAccent">@color/accent_material_dark</item>
Dla Theme.Material.Light
, colorAccent
jest zdefiniowana jako:
<item name="colorAccent">@color/accent_material_light</item>
Przejdź do [sdk_folder]/platforms/android-21/data/res/values/colors_material.xml
i zlokalizuj te kolory:
<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>
Zrzut ekranu z AlertDialog i odpowiadające mu text-color:
Skrót :
Czasami łatwiej jest odczytać wartość koloru (jak na powyższym zdjęciu) i wyszukać ją za pomocą AndroidXRef. Takie podejście nie byłoby przydatne w Twoim przypadku, ponieważ #80cbc4
wskazywałby tylko, że jego kolor akcentu. Nadal trzeba by zlokalizować Widget.Material.Button.Borderless.Colored
i powiązać go z atrybutem buttonBarButtonStyle
.
Zmiana Koloru tekstu przycisku :
Idealnie, powinniśmy stworzyć styl rozszerzający Widget.Material.Button.ButtonBar.AlertDialog
, nadpisujący android:textColor
wewnątrz niego i przypisujący go do atrybutu buttonBarButtonStyle
. Ale to nie zadziała - Twój projekt się nie skompiluje. Dzieje się tak dlatego, że Widget.Material.Button.ButtonBar.AlertDialog
jest stylem niepublicznym i dlatego nie można go rozszerzyć. Możesz to potwierdzić, sprawdzając Link .
Zrobimy następną najlepszą rzecz-rozszerzymy styl rodzica Widget.Material.Button.ButtonBar.AlertDialog
- Widget.Material.Button.Borderless.Colored
co jest publiczne.
<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>
Zauważ, że dodajemy 3 kolejne pozycje po nadpisaniu android:textColor
. Są to style Niepubliczne Widget.Material.Button.ButtonBar.AlertDialog
. Od kiedy my nie można rozszerzyć go bezpośrednio, musimy dołączyć elementy, które definiuje. Uwaga: wartości dimen będą musiały zostać wyszukane i przeniesione do odpowiednich plików res/values(-xxxxx)/dimens.xml
w Twoim projekcie.
Styl CusButtonBarButtonStyle
zostanie przypisany do atrybutu buttonBarButtonStyle
. Ale pytanie brzmi, skąd AlertDialog o tym wie? Z kodu źródłowego:
protected AlertDialog(Context context) {
this(context, resolveDialogTheme(context, 0), true);
}
Podanie 0
jako drugiego argumentu dla resolveDialogTheme(Context, int)
skończy się w else
klauzuli:
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;
}
}
Teraz wiemy, że tematem jest posiadane przez alertDialogTheme
atrybut. Następnie przyjrzymy się temu, na co wskazuje alertDialogTheme
. Wartość tego atrybutu będzie zależeć od motywu nadrzędnego Twojej aktywności. Przejdź do folderu sdk i znajdź values/themes_material.xml
wewnątrz Androida-21. Szukaj alertDialogTheme
. Wyniki:
<!-- 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>
Więc, w oparciu o motyw podstawowy Twojej aktywności, alertDialogTheme
będzie zawierać jedną z tych 3 wartości. Aby powiadomić AlertDialog o CusButtonBarButtonStyle
, musimy nadpisać atrybut alertDialogTheme
w motywie naszej aplikacji. Powiedzmy, że używamy Theme.Material
jako motywu podstawowego.
<style name="AppTheme" parent="android:Theme.Material">
<item name="android:alertDialogTheme">@style/CusAlertDialogTheme</item>
</style>
Z góry wiemy, że alertDialogTheme
wskazuje na Theme.Material.Dialog.Alert
gdy podstawowym motywem Twojej aplikacji jest Theme.Material
. Zatem CusAlertDialogTheme
powinien mieć Theme.Material.Dialog.Alert
jako swój rodzic:
<style name="CusAlertDialogTheme"
parent="android:Theme.Material.Dialog.Alert">
<item name="android:buttonBarButtonStyle">@style/CusButtonBarButtonStyle</item>
</style>
Wynik:
Mam nadzieję wyjaśnić, gdzie są ryby.Więc, zamiast akceptować ryby do jedzenia, czy możesz nauczyć mnie łowić ryby zamiast tego?
P. S. zdaję sobie sprawę, że umieściłem mamuta.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-23 22:25:03
Poza @Vikram doskonała odpowiedź, warto zauważyć, że Android Studio może znacznie uprościć swoją pracę. Musisz tylko najechać myszą na temat, pokaże coś takiego jak podążanie.
actionBarStyle = @style/Widget.AppCompat.Light.ActionBar.Solid
=> @style/Widget.AppCompat.Light.ActionBar.Solid
Możesz również użyć kliknięcia myszką, aby poruszać się między stylami, jak to robisz z normalnym kodem java.
I możesz znaleźć res biblioteki wsparcia w
<sdk root>/extras/android/m2repository/com/android/support/<support library name>/<version number>/<support library>.aar/res
Ale *.aar/res/values/values.xml
zawiera wszystkie wartości i nie jest łatwa do odczytania. Możesz uzyskać oryginalny kod biblioteki wsparcia i zasobów w
https://android.googlesource.com/platform/frameworks/support / + / master
Istnieje przycisk o nazwie tgz
do pobrania aktualnej migawki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 14:39:13