Style inheritance relationship in Android

Style inheritance relationship in Android

[[182651]]

Android's Styles and Themes are very similar to CSS in Web development, which makes it easy for developers to separate page content and layout presentation. The definition of Style and Theme in Android is exactly the same, and the only difference between the two is the concept: Style acts on a single view or control, while Theme is used for Activity or the entire application. Due to the different scopes, Theme needs to contain more items that define attribute values ​​than Style. However, in this article, I will refer to both Style and Theme as Style.

Compared with Web CSS, Android Style has a flaw in that it can only specify a value for an object through android:theme="@style/AppTheme" or style="@style/MyStyle". CSS can define multiple styles on DOM elements through the class attribute to achieve a combination effect. However, Style also has a function that CSS does not have, which is inheritance. (Of course, CSS also has the ability to inherit through tools such as LESS and SASS.)

Introduction to Style Inheritance

According to the official documentation of Android Developers, there are two ways to define Style inheritance: one is to mark the parent Style through parent;

  1. <style name = "GreenText" parent= "@android:style/TextAppearance" >  
  2. <item name = "android:textColor" >#00FF00</item>  
  3. </style>

The other is to use the name of the parent Style as a prefix, and then connect the name of the newly defined Style with a “.”:

  1. <style name = "CodeFont.Red" >
  2. <item name = "android:textColor" >#FF0000</item>
  3. </style>

The second way is to connect sub-Styles to implement multi-layer inheritance:

  1. <style name = "CodeFont.Red.Big" >
  2. <item name = "android:textSize" >30sp</item>
  3. </style>

Compared with the first method, Android restricts the second method in that the Style must be defined by itself, or the parent Style and the child Style must be defined in the same program, and cannot reference a third-party or system Style. After all, the reference to the system Style needs to be prefixed with android: as the namespace.

Secondly, when using Style, for the Style defined in the second way, you must quote its full name, that is, you must include the complete prefix and name:

  1. <EditText
  2. style= "@style/CodeFont.Red.Big"  
  3. ... />

Android does not restrict the first definition method, so all styles defined in the second method can be converted to the first method:

  1. <style name = "Big" parent= "CodeFont.Red" >
  2. <item name = "android:textSize" >30sp</item>
  3. </style>

As long as the name in parent corresponds to the actual defined Style name, it will be fine. However, if the Style name is too concise after changing to the first method, it will easily conflict.

The effect of mixing the two inheritance methods

As mentioned earlier, the effects of the two inheritance methods of Style are the same. What will happen if the two methods are mixed together to define a Style? Let's analyze it with a practical example.

First, define some custom attributes (attr) required for the experiment. (This can reduce the interference of system attributes, because the system always defines values ​​for its attributes, so it may not be possible to tell whether the best effect comes from the system or the defined value)

  1. <?xml version= "1.0" encoding= "utf-8" ?>
  2.  
  3. <resources>
  4.  
  5. < declare -styleable name = "CustomStyle" >
  6.  
  7. <attr name = "customColor" format= "color" />
  8.  
  9. <attr name = "customText" format= "string" />
  10.  
  11. <attr name = "customSize" format= "dimension" />
  12.  
  13. </declare-styleable>
  14.  
  15. </resources>

Next, define a subclass of TextView, get the value of the custom attribute above and assign it to TextView for presentation:

  1. import android.util.TypedValue;
  2.  
  3. import android.widget.TextView;
  4.  
  5. /**
  6.  
  7. * @author Ider
  8.  
  9. */
  10.  
  11. public class StyledTextView extends TextView {
  12.  
  13. public StyledTextView(Context context) {
  14.  
  15. this(context, null );
  16.  
  17. }
  18.  
  19. public StyledTextView(Context context, AttributeSet attrs) {
  20.  
  21. this(context, attrs, 0);
  22.  
  23. }
  24.  
  25. public StyledTextView(Context context, AttributeSet attrs, int defStyleAttr) {
  26.  
  27. super(context, attrs, defStyleAttr);
  28.  
  29. final TypedArray a = context.getTheme()
  30.  
  31. .obtainStyledAttributes(attrs, R.styleable.CustomStyle, defStyleAttr, 0);
  32.  
  33. final CharSequence text = a.getText(R.styleable.CustomStyle_customText);
  34.  
  35. final int color = a.getColor(R.styleable.CustomStyle_customColor, Color.RED);
  36.  
  37. final float   size = a.getDimensionPixelSize(R.styleable.CustomStyle_customSize, 70);
  38.  
  39. a.recycle();
  40.  
  41. setText(text);
  42.  
  43. setTextColor(color);
  44.  
  45. setTextSize(TypedValue.COMPLEX_UNIT_PX, size );
  46.  
  47. }
  48.  
  49. }

Then define the style required for the study

  1. <resources>
  2.  
  3. <style name = "SuperStyleOne" >
  4.  
  5. <item name = "customColor" >@android:color/holo_orange_dark</item>
  6.  
  7. <item name = "customText" >Hello World</item>
  8.  
  9. <item name = "customSize" >30dp</item>
  10.  
  11. </style>
  12.  
  13. <style name = "SuperStyleTwo" >
  14.  
  15. <item name = "customText" >www.iderzheng.com</item>
  16.  
  17. </style>
  18.  
  19. <style name = "SuperStyleOne.SubOne" >
  20.  
  21. <item name = "customColor" >@android:color/holo_blue_dark</item>
  22.  
  23. </style>
  24.  
  25. <style name = "SuperStyleOne.SubTwo" parent= "SuperStyleTwo" >
  26.  
  27. </style>
  28.  
  29. <style name = "SuperStyleOne.SubThree" parent= "SuperStyleTwo" >
  30.  
  31. <item name = "customText" >blog.iderzheng.com</item>
  32.  
  33. </style>
  34.  
  35. </resources>

In the Style defined above, SuperStyleOne will act on the sub-Style by adding a prefix, while SuperStyleTwo will act on the parent. You can see that SubTwo and SubThree mix the two methods.

***Use custom classes in the layout view of the Activity and set different styles

  1. <LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"  
  2.  
  3. xmlns:tools= "http://schemas.android.com/tools"  
  4.  
  5. android:orientation= "vertical"  
  6.  
  7. android:layout_width= "match_parent"  
  8.  
  9. android:layout_height= "match_parent"  
  10.  
  11. android:paddingLeft= "@dimen/activity_horizontal_margin"  
  12.  
  13. android:paddingRight= "@dimen/activity_horizontal_margin"  
  14.  
  15. android:paddingTop= "@dimen/activity_vertical_margin"  
  16.  
  17. android:paddingBottom= "@dimen/activity_vertical_margin"  
  18.  
  19. tools:context= ".MainActivity" >
  20.  
  21. <com.ider.trial.styles.StyledTextView
  22.  
  23. style= "@style/SuperStyleOne"  
  24.  
  25. android:layout_width= "wrap_content"  
  26.  
  27. android:layout_height= "wrap_content" />
  28.  
  29. <com.ider.trial.styles.StyledTextView
  30.  
  31. style= "@style/SuperStyleOne.SubOne"  
  32.  
  33. android:layout_width= "wrap_content"  
  34.  
  35. android:layout_height= "wrap_content" />
  36.  
  37. <com.ider.trial.styles.StyledTextView
  38.  
  39. style= "@style/SuperStyleOne.SubTwo"  
  40.  
  41. android:layout_width= "wrap_content"  
  42.  
  43. android:layout_height= "wrap_content" />
  44.  
  45. <com.ider.trial.styles.StyledTextView
  46.  
  47. style= "@style/SuperStyleOne.SubThree"  
  48.  
  49. android:layout_width= "wrap_content"  
  50.  
  51. android:layout_height= "wrap_content" />
  52.  
  53. </LinearLayout>

The results after running are as follows:

The first and second are both standard ways of using Style. We can see that they correctly obtain the defined property values, and the child Style also correctly inherits and overrides the property values ​​of the parent Style.

For the third and fourth ones, the color they display is the default red (Color.RED) used in the code, and the font value is also derived from the value used in the code, so it is obviously smaller than the first two. This means that they do not inherit the font size and color defined in SuperStyleOne. However, the content defined in SuperStyleTwo is correctly displayed by the third one, which also shows that SubTwo successfully inherits the content of the parent Style specified by parent. The content displayed by the fourth one shows that the overlay effect is also correct.

Before doing this experiment, I always thought that both methods would work at the same time, but specifying with parent has a higher priority than specifying with prefix. That is to say, Android will first look for the value of a certain attribute in the current Style definition. If it is not found, it will go to the parent Style specified by parent. If it is still not found, it will go to the parent Style specified by prefix. However, the above results show that: when parent is used to specify the parent Style, the prefix method has no effect and is only used as the name of the Style. In other words: Android's Style does not support multiple inheritance. Style inheritance can only be done layer by layer in a single line.

It is also easier to understand the system-defined styles. For example, if you open themes_holo.xml, you will see that many of the same contents are "redundantly" defined in two styles: Theme.Holo and Theme.Holo.Light. However, because Theme.Holo.Light uses parent to specify that its parent style is Theme.Light, Theme.Holo.Light does not inherit any property values ​​from Theme.Holo, so such redundancy is necessary.

  1. <style name = "Theme.Holo.Light" parent= "Theme.Light" >
  2.  
  3. ... ... ... ...
  4.  
  5. </style>

Using Theme.Holo.Light as the name of the Style is just to make the name clearer.

References:

  1. Styles and Themes | Android Developers
  2. Android XML theme inheriting from two parent themes? – Stack Overflow
  3. xml – Reason why style attribute does not use the android: namespace prefix – Stack Overflow

<<:  Implementing the animation effect of flipping cards

>>:  Bluepill: LinkedIn's open source iOS parallel UI testing tool

Recommend

Three ways Apple products die

Apple is a company known for its streamlined prod...

With just two changes, Apple gave StyleGANv2 the ability to generate 3D images

How to make an existing 2D GAN into 3D level? Thi...

Why is there 416 pages in the Central Academy of Fine Arts' admission letter?

The Central Academy of Fine Arts admission letter...

“The dragon raises its head”, at what time does it raise its head?

February 21st marks the day when the Dragon raise...

Ruan Yifeng: The seven most important career advices for me (translation)

Nicholas C. Zakas is one of the best JavaScript p...

Developers' Notes: Hot Topics in Mobile Development in 2015

It has been 8 years since Steve Jobs launched the...

After losing 500,000 yuan in an event, I learned 4 "bloody" lessons

In recent days, a marketing director left a messa...

Guide to listing on Android App Market!

The company's product line expanded and multi...

Can quitting sugar make us more beautiful and younger?

Recently, the news that "a woman became whit...