How to explore style in android

I am trying to customize the theme of my application on Android. However, each widget is an excrutiating pain in itself: I have to look for theming this particular widget, and then create a style that hopefully comes from the same style that the widget uses.

Of course, answers about the topics of a particular widget do not always contain information about the basic style, as well as about specific colors.

So, instead of taking fish, is it possible to teach me how to fish?

How to interpret these calls to ObtainStyledAttributes() in widget constructors and extract styles from it? How can I repeat this?

In particular, can you go through the color of the AlertDialog button? What style defines flat button candy + teal text color? How do I get this style if I start with an AlertDialog source and call ObtainStyledAttributes?

+10
android styling
Feb 15 '15 at 6:44
source share
2 answers

I find style to go your way through the framework. What (almost always) comes from the implementation of the widget. Where, I find, everywhere. I will try my best to explain the process through your specific use case - the AlertDialog buttons (s).

Starting at :

You already have this: we start with the source code of the widget. We are specifically trying to find where the AlertDialog buttons get their text color. So, we start by looking at where these buttons come from. Are they explicitly created at runtime? Or are they defined in an xml layout that is bloated?

In the source code, we find that mAlert processes button parameters among other things:

 public void setButton(int whichButton, CharSequence text, Message msg) { mAlert.setButton(whichButton, text, null, msg); } 

mAlert is an instance of the AlertController . In its constructor, we find that the alertDialogStyle attribute defines the xml layout:

 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); 

So, the layout we should pay attention to is alert_dialog.xml - [sdk_folder]/platforms/android-21/data/res/layout/alert_dialog.xml :

The xml layout is pretty long. This is an important part:

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

Now we know that buttons get the style held by the buttonBarButtonStyle attribute.

Go to [sdk_folder]/platforms/android-21/data/res/values/themes.material.xml and search for 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> 

Depending on which topic of parenting activity, buttonBarButtonStyle will refer to one of these two styles. For now, let's assume your activity topic extends Theme.Material . We will look at @style/Widget.Material.Button.ButtonBar.AlertDialog :

Open [sdk_folder]/platforms/android-21/data/res/values/styles_material.xml and search for 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> 

Good. But these values ​​do not help us determine the color of the button text. Now we have to look at the parent style - 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> 

Finally, we find textColor - and its supplied attr/colorAccent , initialized in Theme.Material :

 <item name="colorAccent">@color/accent_material_dark</item> 

For Theme.Material.Light , colorAccent is defined as:

 <item name="colorAccent">@color/accent_material_light</item> 

Find [sdk_folder]/platforms/android-21/data/res/values/colors_material.xml and find these colors:

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

Screenshot with AlertDialog and corresponding text color:

enter image description here

Shortcut

Sometimes it is easier to read the color value (as shown in the picture above) and search for it using AndroidXRef . This approach would not be useful in your case, as #80cbc4 would only indicate its accent color. You still need to find Widget.Material.Button.Borderless.Colored and bind it with the buttonBarButtonStyle attribute.

Change the text color of the button :

Ideally, we should create a style that extends Widget.Material.Button.ButtonBar.AlertDialog , overrides android:textColor inside it and assigns the buttonBarButtonStyle attribute to buttonBarButtonStyle . But this will not work - your project will not compile. This is because Widget.Material.Button.ButtonBar.AlertDialog is non-public and therefore cannot be extended. You can confirm this by setting the Link .

We will do the following: extend the parent style of Widget.Material.Button.ButtonBar.AlertDialog - Widget.Material.Button.Borderless.Colored , which is publicly available.

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

Please note that after overriding android:textColor we will add 3 more elements. This is from the non-public style of Widget.Material.Button.ButtonBar.AlertDialog . Since we cannot distribute it directly, we must include the elements that it defines. Note: the size value (s) must be viewed and transferred to the corresponding res/values(-xxxxx)/dimens.xml files in your project.

The CusButtonBarButtonStyle style will be assigned to the buttonBarButtonStyle attribute. But the question is, how does AlertDialog know about this? From the source code:

 protected AlertDialog(Context context) { this(context, resolveDialogTheme(context, 0), true); } 

resolveDialogTheme(Context, int) 0 because the second argument to resolveDialogTheme(Context, int) will end in 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; } } 

Now we know that the theme is supported by the alertDialogTheme attribute. Then we look at what alertDialogTheme indicates. The value of this attribute will depend on the parent theme of your action. Go to the sdk folder and find the values/themes_material.xml inside android-21. Find alertDialogTheme . Results:

 <!-- 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> 

So, depending on your main activity topic, alertDialogTheme will hold one of these 3 values. To tell AlertDialog about CusButtonBarButtonStyle , we need to override the alertDialogTheme attribute in our application theme. Say we use Theme.Material as our base theme.

 <style name="AppTheme" parent="android:Theme.Material"> <item name="android:alertDialogTheme">@style/CusAlertDialogTheme</item> </style> 

At the top, we know that alertDialogTheme points to Theme.Material.Dialog.Alert when your base theme for your application is Theme.Material . So, CusAlertDialogTheme should have Theme.Material.Dialog.Alert as the parent:

 <style name="CusAlertDialogTheme" parent="android:Theme.Material.Dialog.Alert"> <item name="android:buttonBarButtonStyle">@style/CusButtonBarButtonStyle</item> </style> 

Result:

enter image description here

So, instead of taking fish, can you teach me fish instead?

At least I hope to explain where the fish are.

PS I understand that I published a mammoth.

+27
Feb 23 '15 at 21:23
source share

Aside from the excellent @Vikram answer, it's worth noting that Android Studio can greatly simplify your work. You just need to hover over a topic, it will show something like the following.

 actionBarStyle = @style/Widget.AppCompat.Light.ActionBar.Solid => @style/Widget.AppCompat.Light.ActionBar.Solid 

You can also use the mouse to move between styles, for example, what you do with normal java code.

And you can find the res library support in <sdk root>/extras/android/m2repository/com/android/support/<support library name>/<version number>/<support library>.aar/res

But *.aar/res/values/values.xml contains all the values, and it is not easy to read. You can get the source code and resources of the support library at https://android.googlesource.com/platform/frameworks/support/+/master

To download the current snapshot, there is a button named tgz .

0
Feb 12 '16 at 13:18
source share



All Articles