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ć?

W szczególności, czy możesz mi opowiedzieć o kolorze przycisku? Jaki styl definiuje płaski przycisk lollipop + kolor tekstu teal? Jak Mogę dostać się do tego stylu, jeśli zacznę od źródła AlertDialog i Uzyskamstyledattributes call?
Author: velis, 2015-02-15

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:

Tutaj wpisz opis obrazka

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:

Tutaj wpisz opis obrazka

Więc, zamiast akceptować ryby do jedzenia, czy możesz nauczyć mnie łowić ryby zamiast tego?

Mam nadzieję wyjaśnić, gdzie są ryby.

P. S. zdaję sobie sprawę, że umieściłem mamuta.

 27
Author: Vikram,
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.

 0
Author: cmicat,
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