Believe that every Android
ape in development has encountered the need to customize their own View
needs, if you want to xml
specify some of our own parameters, we need to declare one styleable
, and in the inside to define some of the attr
properties, the process is believed to be more understanding. Of course, attributes do not necessarily need to be View
used in conjunction with one another, for example, I would like to use a Theme
simple configuration of a library in a style
few parameters, what should be done? Today, I was in the encapsulation of a library in this place wasted more time, and finally no way to search the data everywhere, recorded here, I believe it is helpful to everyone.
The relationship between attr and styleable
First of all, be clear, attr
do not rely on styleable
, styleable
just for attr
the convenience of use .
We can define our own properties completely styleable
, such as defining some properties directly in the resources file:
<attr name="custom_attr1" format="string" /><attr name="custom_attr2" format="string" />
Defining one attr
will generate an ID in the R file, so when we go to get this property, we must call the following code:
int[] custom_attrs = {R.attr.custom_attr1,R.custom_attr2};TypedArray typedArray = context.obtainStyledAttributes(set,custom_attrs);
And by defining a styleable
, we can automatically generate a int[in the R File], and the int inside the array is defined in styleable
attr
's ID. So when we get the property, we can use the styleable
array directly to get a series of properties.
<declare-styleable name="custom_attrs"> <attr name="custom_attr1" format="string" /> <attr name="custom_attr2" format="string" /> </declare-styleable>
Get:
TypedArray typedArray = context.obtainStyledAttributes(set,R.styleable.custom_attrs);
As can be known from the above example, define one declare-styleable
, and automatically provide an array of attributes for us when we get the property. In addition, I think declare-styleable
the use of the way to help us we put the relevant attributes together, there is a concept of grouping, the use of properties more explicit scope.
Obtainstyledattributes function Get Property
In fact, we have used the previous obtainStyledAttributes
to get the property, now look at the declaration of this function:
- Obtainattributes (AttributeSet set, int[] attrs)//Get properties in Attrs from the property set in layout
- Obtainstyledattributes (int[] attrs)//Get properties from Attrs in the system theme
- obtainstyledattributes (int resid,int[] attrs)//Read properties from the style defined by the resource file
- Obtainstyledattributes (AttributeSet set, int[] attrs, int defstyleattr, int defstyleres)
This is the most complicated kind of situation, which is followed by detail.
Is it that many overloaded methods have been seen? In fact, you only need to understand the parameters of the method can be used to control the use of various methods. The so-called get property, just need two parameters: first, I need to get those attributes; second: Where do I get these attributes (data source).
Attrs
attrs
: int[], the arguments in each method are the ones that tell the system to get the values of those properties.
Set
set
: Represents a layout
collection of attributes that are added directly from a file View
, such as: android:layout_width="match_parent"。注意,这里面的属性必然是通过
XML 配置添加的,也就是由
layoutinflater 加载进来的布局或者
View ' has this property set.
Now you know why we should at least rewrite the (context, AttributeSet set) constructor When we define the view? Because when not rewritten, we will not be able to get the properties configured in the layout!! Of course, because of this, Layoutinflater will invoke the view's (context context, AttributeSet Attrs) constructor by reflection when inflater the layout.
There are actually two kinds of data sources in set, and of course it will be included in the set. One is the direct use of android:layout_width="wrap_content"
this direct designation, and one is style="@style/somestyle"
specified by this.
Defstyleattr
This parameter is the key to this article, but also the key to customizing a style that can be Theme
configured in, first look at a chestnut bar:
If I wanted to modify all of the styles by setting a style in the system theme, textview
you would typically do this:
<StyleName="Apptheme"Parent="Theme.AppCompat.Light.DarkActionBar" >//set textview in theme style < item name= " Android:textviewstyle "> @style/textviewstyle</item> </style>< style name= "Textviewstyle" parent= "Android:style/widget.textview" >< Span class= "Hljs-rule" > <!--specify some properties-- </STYLE>
The first android:textViewStyle
is actually an ordinary attribute defined in the resource file attr
, it's format="reference"
. The question TextView
is, how do we know what we have defined textviewstyle
? This is actually defStyleAttr
the scenario: Define theme Configurable styles.
Publictextview (context Context, AttributeSet attrs) {//The specified property textviewstyle to Defstyleattr, then the system will go to search theme for the style you configured for this //property this (context, attrs, Com.android. Internal. R.attr.textviewstyle); } public TextView (context Context, AttributeSet attrs, int defstyleattr) {this (context, Attrs, defstyleattr, 0); //finally called to the fourth constructor of view, called obtainstyledattributes TypedArray a = Theme.obtainstyledattributes (attrs, Com.android. Internal. R.styleable.textviewappearance, Defstyleattr, defstyleres); }
Resid=defstyleres
resId or defStyleRes
: Read directly from a style defined in the resource file.
Null
Take a look at the second method, attrs
where does the data come from, except that there is no attribute value source specified in the attribute set? It turns out that we can specify the value of the property directly in the theme, then the NULL
property is read directly from Theme
.
Did you get a little confused about seeing this place? It doesn't matter, patience to see, there is an example, after reading the example you look back to see here the explanation is OK.
Obtainstyledattributes of four parameters
Looking at this method, the returned result is also the set of properties contained in Attrs (int[]) that we care about. What about the data source? A total of 4,,,, set
defStyleAttr
NULL
defStyleRes
If an attribute is defined in more than one place, then whichever is it?
The priority levels are as follows:
set
> defStyleAttr
(Theme configurable style) > defStyleRes
(Default Style) > NULL
(directly specified in the topic)
The chestnuts are finally here!! -github
attr
The resource file is defined as follows:
Defining properties<Declare-styleableName="Custom_attrs" ><attrName="Custom_color1"format="Color" ></Attr><attrName="Custom_color2"format="Color" ></Attr><attrName="Custom_color3"format="Color" ></Attr><attrName="Custom_color4"format="Color" ></Attr><attrName="Custom_color5"format="Color" ></Attr></declare-styleable>//defining theme Configurable style<attrName="Custom_style"format="Reference" ></Attr>//define default style<StyleName= "Default_style" > <item name= "custom_color1" > #ff333333 </< Span class= "Hljs-tag" >item> <item name= " custom_color2 "> #ff333333 </item> <item name= "custom_color3" > #ff333333 </item> <item name= "custom_color4" > #ff333333 </< Span class= "Hljs-tag" >item></STYLE>
styles
The resource file is defined as follows:
<style name="Apptheme"Parent="Theme.AppCompat.Light.DarkActionBar" >Configure Style <item Name="Custom_style" > @style/custom_theme</item>Specify <item name= directly in the topic"Custom_color1" >#ff444444 </item> <item name="Custom_color2" >#ff444444 </item> <item name="Custom_color3" >#ff444444 </item> <item name="Custom_color4" >#ff444444 </item> <item name="Custom_color5" > style <style name="Custom_theme" > <item name= #ff444444 </item> </style>/Themes "Custom_color1" >#ff222222 </item> <item name="Custom_color2" >#ff222222 </item> <item name="Custom_color3" >#ff222222 </item> </style> //style referenced directly in the layout file, The end will be put in set <style name="MyStyle" > <item name="Custom_color1" >#ff111111 </item> < Item name="Custom_color2" >#ff111111 </item> </style>
The layout is defined as follows:
<com.exmp.MyCustomView android:layout_width="wrap_content" android:layout_height="wrap_content" android:style="@style/myStyle" app:custom_color1="#ff000000" > </com.exmp.MyCustomView>
In the constructor of the Mycustomview:
PublicMycustomview (context Context) {this (Context,null);} public MyCustomView (context Context, AttributeSet set) {this ( Context, set, R.attr.custom_style);} public LinearRecyclerView (context Context, AttributeSet set, int Defstyle) {Super (context, set, Defstyle); final TypedArray a = Context.obtainstyledattributes (set, R.styleable.custom_attrs, DefStyle, R.style.default_style)}
Once configured, the TypedArray
values obtained in the properties are:
custom_color1= #ff000000//directly specified in the layout file with highest priority
custom_color2= #ff111111//layout as specified by style, also included in set, priority second
custom_color3= #ff222222//layout style by configuring styles in themes
custom_color4= #ff444444//specified directly by the system theme
custom_color5= #ff444444
Here we see that our default style has no effect because the default style is not effective until defstyle (configurable style in theme) is not 0 and Defstyle is already configured in theme.
TypedArray
We see that after we get the value of the property, we return a Typedarray object, what's the ghost? Typedarray mainly has two functions, the first is to transform the attr
relationship between ID and attribute value array, and the second is to provide some types of automatic conversions, such as getString
when we, if you are @string/hello
set up in this way, TypedArray
will automatically go to the ResId
corresponding string
read from the resource file. In the final analysis, it's all for the convenience of getting property parameters.
Example-github
Back to the beginning
Now we should know how to add to our customizations View
in the topic configurable Style
, mainly through
obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
method to do, note that, defStyleAttr
and defStyleRes
both can be set to 0 to indicate not to search for configurable styles and default styles.
The question comes, if to implement my second requirement for a common class to add a style that can be configured in theme (not primarily for business parties to use the library when configured or to pass in some simple values, this is not the pros and cons of this approach, only to discuss the feasibility)? It's actually very simple:
First define:
<attr name="config_style" reformat="referenc" /> public class ClassNeedConfig { public ClassNeedConfig(Context context) { //因为这个类不是通过Inflate进来的,所以肯定没有set,直接给null就ok //attrs 你需要获取的属性,通常是自己定义的 //指定在Theme中搜索的属性 // 0表示不去搜索默认的样式 TypedArray a = context.obtainStyledAttributes(null,attrs,R.attr.config_style,0); }}
This article mainly refer to:
Android's in-depth understanding of custom properties in Android
The meaning of Defstyle in the third parameter of the custom style in Android and the view's constructor
2016-01-14 Update
The priority is as follows: Set>defstyleattr (theme configurable style) >defstyleres (default style) >null (directly specified in the topic)
This priority needs to be explained that the Defstyleres only takes effect if the defstyleattr is 0 or not configured in the topic, so the above example
custom_color4= #ff444444 instead of 333333, because at this time the defstyleattr we configured.
Wen/Zhu Yunzhinan (Jane book author)
Original link: http://www.jianshu.com/p/61b79e7f88fc
Copyright belongs to the author, please contact the author to obtain authorization, and Mark "book author".
In-depth understanding of Android custom attr Style styleable and its application