Like attention, no more lost, your support means a lot to me!

🔥 Hi, I’m Chouchou. GitHub · Android-Notebook has been included in this article. Welcome to grow up with Chouchou Peng. (Contact information at GitHub)

preface

  • This is often used in Android UI developmentattribute, such as usingandroid:textSet the text box for the copy, usingandroid:srcSet the image. So,android:textHow do I set it to TextView?
  • In this article, I will discuss the LayoutInflater layout and Style/Theme system with you. In addition, don’t miss the suggestions at the end of the article, if you can help, please be sure to like and follow, this is really very important to me.

Related articles

  • The Android | a process how many the Context object (right not much)”
  • The Android | belt you explore LayoutInflater layout principle”
  • The Android | View & fragments & Window of getContext () must return to the Activity?”
  • The Android | about from Android: text to TextView process”

directory


1. Attribute Overview

1.1 Nature of attributes

View Attributes are essentially a key-value pair relationship: attribute name => attribute value.

1.2 How do I define attributes?

To define attributes, use the < declaration-styleable > tag, and define attribute names and attribute value types in the following formats:

Format 1: 1.1 to define the attribute name and attribute value types < attr name = "textColor" format = "reference | color" / > < declare - styleable name = "TextView" > 1.2 reference properties defined above <attr name="textColor" /> </declare-styleable> <declare-styleable name="TextView"> <attr name="text" format="string" localization="suggested" /> </declare-styleable>Copy the code
  • Format 1: divided into two steps, first define the attribute name and attribute value type, and then reference;
  • Format 2: Specify the attribute name and attribute value type in one step.

1.3 Namespaces for attributes

When using an attribute, you need to specify the namespace of the attribute, which is used to distinguish the location of the attribute definition. There are currently four types of namespaces:

  • 1. Tools:xmlns:tools="http://schemas.android.com/tools"

This only works in Android Studio, not at runtime. For example, the background color appears white in the editor preview window, but black at runtime:

tools:background="@android:color/white"
android:background="@android:color/black"
Copy the code
  • 2. Native — Android:xmlns:android="http://schemas.android.com/apk/res/android"

Attrs attributes in the native framework. For example, we can find attrs. XML in Android P, where we can see some well-known attributes:

<! - text color - > < attr name = "textColor" format = "reference | color" / > <! - highlight text color - > < attr name = "textColorHighlight" format = "reference | color" / > <! - highlight text color - > < attr name = "textColorHint" format = "reference | color" / >Copy the code

You can also find this file in the SDK in two ways:

  • Folder: / platform/android SDK – 28 / data/res/values/attrs. The XML

  • Android Studio (switch to project view) :External Libraries/<Android API 28 Platform>/res/values/attrs.xml

(The version you see here is set to compileSdkVersion in app/build.gradle)

  • 3. AppCompat compatible library — no namespace required

Properties defined in the Support library or AndroidX library, such as:

<attr format="color" name="colorAccent"/>
Copy the code

You can also find this file in Android Studio:

  • Android Studio (switch to project view) :External Libraries/Gradle: com. Android. Support: appcompat - v7: [version number] @ aar/res/values/values. The XML
  • 4. Customize — APP:xmlns:app="http://schemas.android.com/apk/res-auto"

Using elimination, the remaining attributes are custom attributes. Includes custom properties in the project and custom properties in the dependency library, such as ConstraintLayout:

<attr format="reference|enum" name="layout_constraintBottom_toBottomOf">
		<enum name="parent" value="0"/>
</attr>
Copy the code

You can also find this file in Android Studio:

  • Android Studio (switch to project view) :External Libraries/Gradle: com. Android. Support: the constraint, the constraint - layout: [version number] @ aar/res/values/values. The XML

2. Style overview

One caveat: although the style and theme look alike, although they are very different!

2.1 The nature of style

A Style is a set of key-value pairs, essentially a set of reusable View properties that represent a type of Widget. Something like this:

<style name="BaseTextViewStyle">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:includeFontPadding">false</item>
</style>
Copy the code

2.2 The role of styles

Using styles enables reuse of attribute values, avoiding defining duplicate attribute values and facilitating project maintenance.

As business functions are superimposed, there must be some common, reusable styles in the project. For example, label styles appear in many places:

As you can see, these labels are different colors, but they have something in common: rounded corners, border widths, font sizes, and inside margins. If styles are not used, these same attributes need to be declared repeatedly at each tag.

At this point, if the UI needs to change the inner margins of all the tags, then it needs to change the attribute values of each note, which is tedious. With styles, duplicate attributes can be folded into a single style, and when the style needs to be changed, only one file needs to be changed, like this:

<style name="smallTagStyle" parent="BaseTextViewStyle">
    <item name="android:paddingTop">3dp</item>
    <item name="android:paddingBottom">3dp</item>
    <item name="android:paddingLeft">4dp</item>
    <item name="android:paddingRight">4dp</item>
    <item name="android:textSize">10sp</item>
    <item name="android:maxLines">1</item>
    <item name="android:ellipsize">end</item>
</style>
Copy the code

2.3 Using styles in XML

To use a style, use style=””, like this:

<TextView Android :text=" tag "style="@style/smallTagStyle"/>Copy the code

I’ll talk more about how these two attributes work later.

2.4 Style considerations

  • Styles are not passed across multiple levels

A style works only on the View that uses it, not on its child views. For example, if a ViewGroup has three buttons, if you set MyStyle to this ViewGroup, then only the ViewGroup is valid, not the three buttons.


3. Topic Overview

3.1 Nature of the subject

Like the style, the ** Theme ** is also a collection of key-value pairs, but they are very different in nature. The essence of a style is a reusable set of View properties, while a theme is a referenced set of named resources. Something like this:

<style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="dialogTheme">@style/customDialog</item>
</style>
Copy the code

3.2 The Role of topics

A topic background defines a collection of resources that can be referenced in multiple places, in styles, layout files, code, and so on. Using a theme, you can easily replace the value of an attribute globally.

For example, first you can define a set of dark themes and a set of light themes:

<style name="BlackTheme" parent="AppBaseTheme">
    <item name="colorPrimary">@color/black</item>
</style>

<style name="WhiteTheme" parent="AppBaseTheme">
    <item name="colorPrimary">@color/white</item>
</style>
Copy the code

Then, you reference it where you need thematization, something like this:

The < ViewGroup... android:background="? attr/colorPrimary">Copy the code

If BlackTheme is applied, the background of the ViewGroup is black; Conversely, if a WhiteTheme is referenced, the background of the ViewGroup is white.

To use topic attributes in XML, use? Gets the value represented by the semantic attribute in this topic. I’ve summarized all the formats here:

format describe
android:background=”? attr/colorAccent /
android:background=”? colorAccent (“? Attr /colorAccent”
android:background=”? android:attr/colorAccent (The namespace of the property is Android)
android:background=”? android:colorAccent (“? Android: attr/colorAccent “)

3.3 Using themes in XML

To use themes in XML, you need to use Android: Theme, something like this:

1. <application... Android :theme="@style/BlackTheme "> 2. Android :theme="@style/BlackTheme "/> View layer <ConstraintLayout... android:theme="@style/BlackTheme ">Copy the code

Note that Android :theme essentially uses ContextThemeWrapper to use the theme as well, as I explained in two previous articles: The Android | View & fragments & Window of getContext () must return to the Activity?” , the Android | belt you explore LayoutInflater layout principles. Let me repeat it briefly:

LayoutInflater.java

private static final int[] ATTRS_THEME = new int[] { com.android.internal.R.attr.theme }; final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME); final int themeResId = ta.getResourceId(0, 0); if (themeResId ! = 0) {construct ContextThemeWrapper context = new ContextThemeWrapper(context, themeResId); }Copy the code
  • 1. When layoutInflaters parse layouts, they need to instantiate views based on XML.
  • 2. During the parsing process, it will determine whether the View is usedandroid:theme;
  • 3. If used, wrap the Context with ContextThemeWrapper and use the wrapper class for instantiation of the child View.

3.4 Using themes in code

To use a Theme in your code, use ContextThemeWrapper & Theme, which provide methods for setting the Theme resource:

ContextThemeWrapper.java

@Override public void setTheme(int resid) { if (mThemeResource ! = resid) { mThemeResource = resid; Theme#applyStyle(...) initializeTheme(); }}Copy the code

Theme.java

public void applyStyle(int resId, boolean force) {
    mThemeImpl.applyStyle(resId, force);
}
Copy the code

When a new ContextThemeWrapper is constructed, it allocates new Theme and Resources instances. Now, where does the final theme come into play? I said in verse 4.

3.5 Topics to note

  • Topics are passed across multiple levels

Unlike styles, themes are also valid for lower levels. For example, suppose the Activity is set to a BlackTheme, which is valid for all views on the Activity. At this point, if the View specifies android: Theme separately, the View will use the new theme separately.

  • Do not use Application Context to load resources

Application is a subclass of ContextWrapper, so the Application Context does not retain any information about the theme, and the theme set in the manifest is only used as the default choice for activities that do not explicitly set the theme background. Do not use the Application Context to load available resources.


4. Problem regression

Now, let’s go back to the process of going from Android: Text to TextView. This is how to parse the android: Text property value into a TextView. This process is the process of parsing LayoutInflater layout, I wrote an article before the core process of layout analysis is discussed: the Android | belt you explore LayoutInflater layout principles, and core process is as follows:

4.1 AttributeSet

In the previous article, we learned that LayoutInflaters instantiate views by reflection. The args parameters are Context & AttributeSet:

  • Context: the Context, possibly the wrapper class ContextThemeWrapper
  • AttributeSet: A list of attributes to which all attributes declared by the View in XML are resolved.

LayoutInflater.java

final View view = constructor.newInstance(args);
Copy the code

For example, suppose we have a layout file, and we try to print the AttributeSet passed in when the LayoutInflater instantiates the View:

<... MyTextView Android :text=" tag "Android :theme="@style/BlackTheme" Android :textColor="? colorPrimary" style="@style/smallTagStyle"/>Copy the code

MyTextView.java

public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); There are four attributes for (int index = 0; index < attrs.getAttributeCount(); index++) { System.out.println(attrs.getAttributeName(index) + " = " + attrs.getAttributeValue(index)); }}Copy the code

AttributeSet.java

Return attribute name String (excluding namespace) public String getAttributeValue(int index); Public String getAttributeValue(int index);Copy the code

The output is as follows:

theme = @2131558563 textColor = ? 2130837590 text = Tag style = @2131558752Copy the code

As you can see, AttributeSet only contains attributes that are declared directly in the XML. For attributes of reference types, AttributeSet simply records the resource ID, not unbundle it.

4.2 TypedArray

To retrieve the real property value, you need a TypeArray and an array of ints (where the int value is the property ID). Something like this:

private static final int[] mAttr = {android.R.attr.textColor, android.R.attr.layout_width}; private static final int ATTR_ANDROID_TEXTCOLOR = 0; private static final int ATTR_ANDROID_LAYOUT_WIDTH = 1; 1. Loading the properties from the AttributeSet TypedArray a = context. ObtainStyledAttributes (attrs, mAttr); for (int index = 0; index < a.getIndexCount(); Index ++) {2. Parse each attribute switch (index) {case ATTR_ANDROID_TEXTCOLOR: system.out.println (" Attributes: " + a.getColor(index, Color.RED)); break; case ATTR_ANDROID_LAYOUT_WIDTH: System.out.println("attributes : " + a.getInt(index, 0)); break; }}Copy the code

In this case, the mAttr array is two ints, android.r.attt.textColor and Android.r.Attt.layout_width, representing the property we are interested in. When we apply mAttr to Context#obtainStyledAttributes(), only the attributes we are interested in are resolved.

Output:

-16777216, i.e. : color. BLACK => This value comes from? Attr /colorPrimary refers to the theme attribute -2, i.e. WRAP_CONTENT => This value comes from the style attribute referenced in @style/smallTagStyleCopy the code

Note that in most cases you don’t need to hardcode in your code, but instead use the < declaration-styleable > tag. The compiler will automatically declare the same array for us in r.Java, like this:

<declare-styleable name="MyTextView">
    <attr name="android:textColor" />
    <attr name="android:layout_width" />
</declare-styleable>
Copy the code

R.java

Public static final int[] MyTextView={equivalent to mAttr 0x01010098, 0x010100F4}; public static final int MyTextView_android_textColor=0; ATTR_ANDROID_TEXTCOLOR public static final int MyTextView_android_layout_width=1; The equivalent of ATTR_ANDROID_LAYOUT_WIDTHCopy the code

Tip: The advantage of using R.style. design is to avoid parsing unwanted properties.

4.3 Context#obtainStyledAttributes() Specifies the value sequence

Now, let’s discuss the order in which obtainStyledAttributes() parses attribute values. When an attribute is found at a higher level, the value of the attribute is preferentially returned: View > Style > Default Style > Theme.

  • View

Refers to attributes directly specified by XML, like this:

<TextView
    ...
    android:textColor="@color/black"/>
Copy the code
  • Style

Refers to an attribute specified by XML in a style, like this:

<TextView
    ...
    android:textColor="@style/colorTag"/>

<style name="colorTag">
    <item name="android:textColor">@color/black</item>
Copy the code
  • Default Style

It is the third argument to the constructor, similar to TextView:

public AppCompatTextView(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.textViewStyle); } public AppCompatTextView(Context context, AttributeSet attrs, @AttrRes int defStyleAttr) { super(TintContextWrapper.wrap(context), attrs, defStyleAttr); . }Copy the code

Among them, the android. State Richard armitage TTR event. TextViewStyle said textViewStyle attributes of reference topics, the value specified in the theme resource is a style of resources:

<item name="android:textViewStyle">@style/Widget.AppCompat.TextView</item>
Copy the code

Tip: As you can see from @attrres, defStyleAttr must refer to the topic attribute.

  • Default Style Resource

Refers to the style resource specified in the View constructor, which is the third argument to the constructor:

public View(Context context, AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
}
Copy the code

Tip: As you can see from @styleres, defStyleRes must refer to style resources.

  • Theme

If none of the levels above match the attribute, then the topic attribute in the topic is used, like this:

<style name="AppTheme" parent="...">
    ...
    <item name="android:textColor">@color/black</item>
</style>
Copy the code

5. Attribute value types

As mentioned above, defining attributes requires specifying: attribute name and attribute value type. Attribute value type can be divided into resource class and special class

5.1 the resource class

Attribute value type describe TypedArray
fraction The percentage of getFraction(…)
float Floating point Numbers getFloat(…)
boolean Boolean value getBoolean(…)
color Color value getColor(…)
string string getString(…)
dimension Size value GetDimensionPixelOffset (…).

getDimensionPixelSize(…)

getDimension(…)
integer An integer value getInt(…)

getInteger(…)

5.2 special class

Attribute value type describe TypedArray
flag Sign a getInt(…)
enum Enumerated values Get int (…). Etc.
reference The resource reference getDrawable(…) Etc.

Fraction is a fraction.

  • 1. Attribute definition
<declare-styleable name="RotateDrawable">
    // ...
    <attr name="pivotX" format="float|fraction" />
    <attr name="pivotY" format="float|fraction" />
    <attr name="drawable" />
</declare-styleable>
Copy the code
  • Setting property values
<? The XML version = "1.0" encoding = "utf-8"? > <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:pivotX="50%" android:pivotY="50%" android:drawable="@drawable/fifth"> </animated-rotate>Copy the code
  • Application (RotateDrawable)
If (a.h asValue (R.s tyleable RotateDrawable_pivotX)) {/ / take out the corresponding TypedValue final TypedValue TV = a.peekValue(R.styleable.RotateDrawable_pivotX); MPivotXRel = tv.type == typeDValue.type_fraction; // Obtain the final value state.mpivotX = state.mpivotxrel? TV. GetFraction (1.0 f to 1.0 f) : TV. GetFloat (); }Copy the code

As you can see, pivotX supports both float and fraction, so you will need to determine the type of the attribute value using TypedValue#type, calling TypedValue#getFraction() and TypedValue#getFloat(), respectively.

GetFraction (float Base,float pBase) takes two arguments as base, and the final return value is base * percentage. For example, when the property value is set to 50%, the return value is Base *50%; When the property value is set to 50%p, the return value is pbase*50%.


6. Summary

  • Takes an exam the advice
    • Understand the difference between a style and a theme, which are very different: a style is a reusable collection of View properties, while a theme is a named collection of resources.
    • View > Style > Default Style > Theme

The resources

  • The Android system | style theme background and style – the Android Developers
  • What’s Your Text’s Appearance? By Nick Butcher (Google)
  • Style Resource — Android Developers
  • Styles and Themes — Android Developers
  • Creating a Custom View Class – Android Developers
  • Best Practices for Themes and Styles — Android Dev Summit ’18
  • Android Themes & Styles demystified — Google I/O 2016
  • The Definitive Guide to Android Programming by Bill Phillips, Chris Stewart, and Kristin Marsicano

Recommended reading

  • Cryptography | is Base64 encryption algorithm?
  • Interview questions | back algorithm framework to solve problems
  • The interview questions | list questions summary algorithm
  • Java | show you understand the ServiceLoader principle and design idea
  • Android | interview will ask Handler, are you sure you don’t look at it?
  • Android | show you understand NativeAllocationRegistry principle and design idea
  • Computer composition principle | Unicode utf-8 and what is the relationship?
  • | why floating-point arithmetic of computer constitute principle is not accurate? (Ali written test)
  • Computer network | graphic DNS & HTTPDNS principle

Thank you! Your “like” is the biggest encouragement for me! Welcome to attentionPeng XuruiThe lot!