安卓开发学习之017 自定义控件之属性获取
来源:互联网 发布:tv365网络电视下载 编辑:程序博客网 时间:2024/09/21 09:28
每每看到别人写的好看又实用的控件总是羡慕不已,你是不是也跟我一样,想自己动手写属于自己的控件?希望这篇文章可以帮到你们。
谈到自定义控件就少不了属性的配置和获取,通常需要以下几个步骤:
1.通过<declare-styleable>为自定义View添加属性 2.自定义View的Java文件 3.在xml中为引用自定义View并给相应的属性声明属性值 4.在运行时(一般为构造函数)获取属性值 5.将获取到的属性值应用到View
一、定义控件属性
在res/values/attrs.xml下通过元素声明需要的属性
通常格式为
<declare-styleable name="CustomizeStyle"> <attr name="attr_name" format="string" /> </declare-styleable>
当然直接用attr 定义属性也是可以的,如下
<attr name="attr_name" format="string" />
关于二者区别稍后通过实例做介绍
其中name为属性的名字,format 为属性的格式
format共有十种值可选
下面为本文所使用的属性文件
/res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources> <!-- reference:参考某一资源ID color:颜色值 boolean:布尔值 dimension:尺寸值 float:浮点值 integer:整型值 string:字符串 fraction:百分数 enum:枚举值 多值选一 flag:位或运算,多值组合,用“|”分隔 --> <declare-styleable name="CustomTextViewStyle"> <attr name="description" format="string"/> <attr name="text_size" format="dimension"/> <attr name="text_color" format="color"/> <attr name="text_content" format="string"/> <attr name="padding" format="dimension"/> <attr name="float_value" format="float"/> <attr name="integer_value" format="integer"/> <attr name="boolean_value" format="boolean"/> <attr name="fraction_value" format="fraction"/> <attr name="string_value" format="string"/> <attr name="dimension_value" format="dimension"/> <attr name="color_value" format="color"/> <attr name="reference_drawable_value" format="reference"/> <attr name="reference_array_value" format="reference"/> <attr name="enum_value" format="enum"> <enum name="horizontal" value="0"/> <enum name="vertical" value="1"/> </attr> <attr name="flag_value"> <flag name="normal" value="0"/> <flag name="bold" value="1"/> <flag name="italic" value="2"/> </attr> </declare-styleable> <attr name="CustomizeStyle" format="reference"/></resources>
关于二者定义方法的异同:
相同:都会在R文件attr类中生成ID
public static final class attr { public static final int CustomizeStyle=0x7f010000; public static final int description=0x7f010041; public static final int text_size=0x7f010042; public static final int text_color=0x7f010043; public static final int text_content=0x7f010044; public static final int padding=0x7f010045; public static final int float_value=0x7f010046; public static final int integer_value=0x7f010047; public static final int boolean_value=0x7f010048; public static final int fraction_value=0x7f010049; public static final int string_value=0x7f01004a; public static final int dimension_value=0x7f01004b; public static final int color_value=0x7f01004c; public static final int reference_drawable_value=0x7f01004d; public static final int reference_array_value=0x7f01004e; public static final int enum_value=0x7f01004f; public static final int flag_value=0x7f010050;}
不同:通过< declare-styleable>标签定义的属性还会在R文件styleable类中生成相关属性
public static final class styleable { public static final int[] CustomTextViewStyle = { 0x7f010041, 0x7f010042, 0x7f010043, 0x7f010044, 0x7f010045, 0x7f010046, 0x7f010047, 0x7f010048, 0x7f010049, 0x7f01004a, 0x7f01004b, 0x7f01004c, 0x7f01004d, 0x7f01004e, 0x7f01004f, 0x7f010050 }; public static final int CustomTextViewStyle_description = 0; public static final int CustomTextViewStyle_text_size = 1; public static final int CustomTextViewStyle_text_color = 2; public static final int CustomTextViewStyle_text_content = 3; public static final int CustomTextViewStyle_padding = 4; public static final int CustomTextViewStyle_float_value = 5; public static final int CustomTextViewStyle_integer_value = 6; public static final int CustomTextViewStyle_boolean_value = 7; public static final int CustomTextViewStyle_fraction_value = 8; public static final int CustomTextViewStyle_string_value = 9; public static final int CustomTextViewStyle_dimension_value = 10; public static final int CustomTextViewStyle_color_value = 11; public static final int CustomTextViewStyle_reference_drawable_value = 12; public static final int CustomTextViewStyle_reference_array_value = 13; public static final int CustomTextViewStyle_enum_value = 14; public static final int CustomTextViewStyle_flag_value = 15; }
可以看出通过< declare-styleable>标签定义的属性,
在styleable类中生成了一个数组,数组下标索引用别名进行了定义
如“CustomTextViewStyle_description = 0”,数组中的值与attr类中的值一一对应。
在后面取值时会用到这个数组和下标索引值,
如果是直接通过attr标签定义的属性,可以自己构建这个数组,然后获取值,后面会讲到
跳转查看
二、自定义View的实现(.Java)
在包中新建CustomTextView.java 文件 继承自TextView,简单写几个构造函数,其他后续再扩展
public class CustomTextView extends TextView { //在java代码中通过new CustomTextView(context) 时会调用此方法 public CustomTextView(Context context) { super(context); } //在XML中引用自定义控件,会调用此方法 public CustomTextView(Context context, AttributeSet attrs) { super(context, attrs); } public CustomTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public CustomTextView(Context context, AttributeSet attrs, int defStyle, int defStyleRes) { super(context, attrs, defStyle, defStyleRes); }
三、在XML中使用自定义控件并给属性赋值
首先要在布局XML文件中申明控件所使用的命名空间.
命名空间跟C++中的概念很相同 using namespace std;
就可以在代码中直接使用命名空间中的成员 cout 等等
先看下系统所使用的命名空间
xmlns:android=”http://schemas.android.com/apk/res/android”
对于这个我们我们不陌生,我们最长用的就是
android:id="",android:layout_width=""
如果去掉这个命名空间,我们就不能在控件中使用android这个标签了
接下来这个是我们自定义的命名空间
xmlns: myAttr=”http://schemas.android.com/apk/res-auto”
myAttr是命名空间名字,后面的是地址
“res-auto”在早期是要替换成/res/自己项目的包名
使用自定义控件
格式如下
<com.antex.customview.CustomTextView android:id="@+id/textview0" android:layout_width="wrap_content" android:layout_height="wrap_content" myAttr:text_color="@color/colorAccent" myAttr:text_content="text from xml" myAttr:text_size="12sp"/>
下面为本文布局文件
res/fragment_custom_view.xml
<LinearLayout android:id="@+id/linearLayout" xmlns:android="http://schemas.android.com/apk/res/android"xmlns:myAttr="http://schemas.android.com/apk/com.antex.customview" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".CustomViewActivityFragment" tools:showIn="@layout/activity_custom_view" > <com.antex.customview.CustomTextView android:id="@+id/textview0" text="@string/app_name" android:layout_width="wrap_content" android:layout_height="wrap_content" myAttr:text_color="@color/colorAccent" myAttr:text_content="text from xml" myAttr:text_size="12sp" style="@style/CustomStyle"/> <com.antex.customview.CustomTextView android:id="@+id/textview1" style="@style/CustomStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <com.antex.customview.CustomTextView android:id="@+id/textview2" android:layout_width="wrap_content" android:layout_height="wrap_content" myAttr:boolean_value="true" myAttr:color_value="@color/colorAccent" myAttr:description="Show all type Attribute" myAttr:dimension_value="10.5dp" myAttr:enum_value="horizontal" myAttr:flag_value="bold|italic" myAttr:float_value="10.1" myAttr:fraction_value="30%p" myAttr:integer_value="@integer/default_int" myAttr:reference_array_value="@array/String_Array" myAttr:reference_drawable_value="@mipmap/yxs" myAttr:string_value="stringvalue" /> <com.antex.customview.CustomTextView android:id="@+id/textview3" android:layout_width="wrap_content" android:layout_height="wrap_content" myAttr:description="default none attr setting"/> <com.antex.customview.CustomTextView android:id="@+id/textview4" android:layout_width="wrap_content" android:layout_height="wrap_content" myAttr:description="default none attr setting"/> <RadioGroup android:id="@+id/radiaGroup" android:layout_width="match_parent" android:layout_height="wrap_content"> <RadioButton android:id="@+id/rb1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="AppTheme.WithCustomizeStyle.Activity.WithValues.withCustomizeStyle"/> <RadioButton android:id="@+id/rb2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="AppTheme.WithCustomizeStyle.Activity.WithValues"/> <RadioButton android:id="@+id/rb3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="AppTheme.WithCustomizeStyle.Activity.NoValues"/> <RadioButton android:id="@+id/rb4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="AppTheme.NoCustomizeStyle.Activity.NoValuess"/> </RadioGroup></LinearLayout>
说明:
id为 textview0 直接在XML中设置了属性值,并且也指定了Style
id为 textview1 通过Style 设置属性
id为 textview2 用来介绍 attr 十种类型数据获取 和defStyleAttr=0 defStyleRes=0时取值情况
id为 textview3 演示defStyleAttr=0时取值情况
id为 textview4 演示defStyleAttr!=0 defStyleRes!=0时取值情况
还有一个RadioGroup 用来切换当前应用的Application和Activity的theme
四、java文件中获取属性
获取属性值函数:obtainStyledAttributes
其函数定义为
public final TypedArray obtainStyledAttributes( AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { return getTheme().obtainStyledAttributes( set, attrs, defStyleAttr, defStyleRes); }
参数说明:
4个参数的意思分别是:
set:属性值的集合,一般为第二个构造函数中的attrs
attrs:我们要获取的属性的资源ID的一个数组,在本文中为 R.styleable
.CustomTextViewStyle
defStyleAttr:这个是当前Theme中的一个attribute,是指向style的一个引用,当在layout xml中和style中都没有为View指定属性时,会从Theme中这个attribute指向的Style中查找相应的属性值,如果这个参数传入0表示不向Theme中搜索默认值。在本文中为R.attr.CustomizeStyle
defStyleRes:这个也是指向一个Style的资源ID,但是仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用。在本文中为R.style.DefaultCustomizeStyle
函数返回值:
TypedArray 是一个类,包含要获取值的一个集合
下面我们通过代码来讲解
4.1 TypedArray使用详解:attr十种属性值获取
4.1.1 TypedArray中的方法
4.1.2 TypedValue中值类型
hehe
/** The value contains no data. */ public static final int TYPE_NULL = 0x00; /** The <var>data</var> field holds a resource identifier. */ public static final int TYPE_REFERENCE = 0x01; /** The <var>data</var> field holds an attribute resource * identifier (referencing an attribute in the current theme * style, not a resource entry). */ public static final int TYPE_ATTRIBUTE = 0x02; /** The <var>string</var> field holds string data. In addition, if * <var>data</var> is non-zero then it is the string block * index of the string and <var>assetCookie</var> is the set of * assets the string came from. */ public static final int TYPE_STRING = 0x03; /** The <var>data</var> field holds an IEEE 754 floating point number. */ public static final int TYPE_FLOAT = 0x04; /** The <var>data</var> field holds a complex number encoding a * dimension value. */ public static final int TYPE_DIMENSION = 0x05; /** The <var>data</var> field holds a complex number encoding a fraction * of a container. */ public static final int TYPE_FRACTION = 0x06; /** Identifies the start of plain integer values. Any type value * from this to {@link #TYPE_LAST_INT} means the * <var>data</var> field holds a generic integer value. */ public static final int TYPE_FIRST_INT = 0x10; /** The <var>data</var> field holds a number that was * originally specified in decimal. */ public static final int TYPE_INT_DEC = 0x10; /** The <var>data</var> field holds a number that was * originally specified in hexadecimal (0xn). */ public static final int TYPE_INT_HEX = 0x11; /** The <var>data</var> field holds 0 or 1 that was originally * specified as "false" or "true". */ public static final int TYPE_INT_BOOLEAN = 0x12; /** Identifies the start of integer values that were specified as * color constants (starting with '#'). */ public static final int TYPE_FIRST_COLOR_INT = 0x1c; /** The <var>data</var> field holds a color that was originally * specified as #aarrggbb. */ public static final int TYPE_INT_COLOR_ARGB8 = 0x1c; /** The <var>data</var> field holds a color that was originally * specified as #rrggbb. */ public static final int TYPE_INT_COLOR_RGB8 = 0x1d; /** The <var>data</var> field holds a color that was originally * specified as #argb. */ public static final int TYPE_INT_COLOR_ARGB4 = 0x1e; /** The <var>data</var> field holds a color that was originally * specified as #rgb. */ public static final int TYPE_INT_COLOR_RGB4 = 0x1f; /** Identifies the end of integer values that were specified as color * constants. */ public static final int TYPE_LAST_COLOR_INT = 0x1f; /** Identifies the end of plain integer values. */ public static final int TYPE_LAST_INT = 0x1f;
4.1.3 利用TypedArray获取属性值
为了方便,我们指定defStyleAttr和defStyleRes都为0
我们来打印 id为 textview2 这个控件中的各个值
/** * 介绍TypedArray使用方法 * 获取 attr中formate 十种类型属性值 * float,integer,boolean,fraction,string,dimension,color,reference,enum,flag * <p/> * * @param context 上下文环境 * @param attrs 属性集合 */ private void printAttributes(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable .CustomTextViewStyle, 0, 0); float float_value = typedArray.getFloat(R.styleable.CustomTextViewStyle_float_value, 0f); int integer_value = typedArray.getInteger(R.styleable.CustomTextViewStyle_integer_value, 0); boolean boolean_value = typedArray.getBoolean(R.styleable .CustomTextViewStyle_boolean_value, false); //public float getFraction (int index, int base, int pbase, float defValue) // 如果值为10% 则 fraction_value=10%*base //如果值格式为10%p,则fraction_value=10%*pbase float fraction_value = typedArray.getFraction(R.styleable .CustomTextViewStyle_fraction_value, 1, 1, 0); String string_value = typedArray.getString(R.styleable.CustomTextViewStyle_string_value); //获取像素值,浮点数 eg:27.5625 float dimension_value_float = typedArray.getDimension(R.styleable .CustomTextViewStyle_dimension_value, 0f); //将取得浮点像素值四舍五入 eg:28 int dimension_value = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_dimension_value, 0); //将取得浮点像素值直接截取整数部分 eg:27 int dimension_value_offset_ = typedArray.getDimensionPixelOffset(R.styleable .CustomTextViewStyle_dimension_value, 0); int color_value = typedArray.getColor(R.styleable.CustomTextViewStyle_color_value, 0); int reference_drawable_value = typedArray.getResourceId(R.styleable .CustomTextViewStyle_reference_drawable_value, 0); int reference_array_value = typedArray.getResourceId(R.styleable .CustomTextViewStyle_reference_array_value, 0); int enum_value = typedArray.getInt(R.styleable.CustomTextViewStyle_enum_value, -1); int flag_value = typedArray.getInt(R.styleable.CustomTextViewStyle_flag_value, -1); System.out.println("float_value = [" + float_value + "], integer_value = [" + integer_value + "], " + "boolean_value = [" + boolean_value + "], fraction_value = [" + fraction_value + "], string_value = [" + string_value + "], dimension_value = [" + dimension_value + "], color_value = [" + color_value + "], " + "reference_drawable_value =" + " [0x" + Integer.toHexString(reference_drawable_value) + "], enum_value = [" + enum_value + "], " + "flag_value1 = [" + flag_value + "]"); //后期数据处理,设置左边图片 Drawable drawable; drawable = typedArray.getDrawable(R.styleable.CustomTextViewStyle_reference_drawable_value); //or drawable = context.getDrawable(reference_drawable_value); drawable.setBounds(new Rect(0, 0, 50, 50)); setCompoundDrawables(drawable, null, null, null); //设置文字是否大写,斜体 if (flag_value >= 0) { Typeface typeface = getTypeface(); setTypeface(Typeface.defaultFromStyle(flag_value)); } //其他方法getTextArray CharSequence[] arrays; arrays = typedArray.getTextArray(R.styleable.CustomTextViewStyle_reference_array_value); //or arrays = context.getResources().getTextArray(reference_array_value); for (int i = 0; i < arrays.length; i++) { System.out.println("arrays[" + i + "] = " + arrays[i]); } //遍历TypedArray for (int i = 0, m = typedArray.getIndexCount(); i < m; i++) { System.out.println("typedArray" + i + " type= " + typedArray.getType(i) + " value=" + typedArray.getString(i)); } int textsize = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_text_size, 10); int textcolor = typedArray.getColor(R.styleable.CustomTextViewStyle_text_color, Color .BLACK); String text = typedArray.getString(R.styleable.CustomTextViewStyle_text_content); int padding = typedArray.getDimensionPixelSize(R.styleable.CustomTextViewStyle_padding, 0); setTextColor(textcolor); setTextSize(textsize); setText(text); setPadding(padding, padding, padding, padding); typedArray.recycle();
4.2 obtainStyledAttributes方法详解
TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr,int defStyleRes)
在4.1.3节中,我们对这个方法有了简单的认识
下面我们来看看后面两个参数不为0的情况下,是如何取值的.
4.2.1首先我们需要定义一些style
res/values/styles.xml
我们在Application的theme中增加几个基础属性
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="text_size">8sp</item> <item name="padding">15dp</item> <item name="text_content">@string/from_App_theme</item> <item name="text_color">#f00</item> </style>
再此基础上又定义了一个Style,包含属性值“CustomizeStyle“(方法中第三个参数defStyleAttr),它又引用一个Style
<style name="AppTheme.WithCustomizeStyle"> <item name="CustomizeStyle">@style/CustomizeStyleInAppTheme</item> </style> <style name="CustomizeStyleInAppTheme"> <item name="text_size">10sp</item> <item name="padding">2dp</item> <item name="text_color">@color/colorPrimaryDark</item> <item name="text_content">text from AppTheme refrence</item> </style>
还定义了个方法中第四个参数defStyleRes指向的的style
<style name="DefaultCustomizeStyle"> <item name="text_content">text form DefaultCustomizeStyle</item> <item name="padding">4dp</item> <!--<item name="text_color">#7ff</item>--> </style>
此外定义了若干Activity的theme,有包含属性”CustomizeStyle“和不包含此属性的
全部代码为
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="text_size">8sp</item> <item name="padding">15dp</item> <item name="text_content">@string/from_App_theme</item> <item name="text_color">#f00</item> </style> <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/> <style name="AppTheme.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style> <style name="AppTheme.NoCustomizeStyle"/> <style name="AppTheme.WithCustomizeStyle"> <item name="CustomizeStyle">@style/CustomizeStyleInAppTheme</item></style> <style name="AppTheme.NoCustomizeStyle.Activity"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style> <style name="AppTheme.WithCustomizeStyle.Activity"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item> </style> <style name="AppTheme.NoCustomizeStyle.Activity.NoValues"/> <style name="AppTheme.WithCustomizeStyle.Activity.NoValues"/> <style name="AppTheme.NoCustomizeStyle.Activity.WithValues"> <item name="text_color">#7ff</item> <item name="text_size">12sp</item> <item name="text_content">@string/from_Activity_theme</item> <item name="padding">15dp</item> </style> <style name="AppTheme.WithCustomizeStyle.Activity.WithValues"> <item name="text_color">#f0f</item> <item name="text_size">12sp</item> <item name="text_content">@string/from_Activity_theme</item> <item name="padding">15dp</item> </style> <style name="AppTheme.NoCustomizeStyle.Activity.WithValues.withCustomizeStyle"> <item name="CustomizeStyle">@style/CustomizeStyleInActivityTheme</item> </style> <style name="AppTheme.WithCustomizeStyle.Activity.WithValues.withCustomizeStyle"> <item name="CustomizeStyle">@style/CustomizeStyleInActivityTheme</item> </style> <style name="CustomizeStyleInAppTheme"> <item name="text_size">10sp</item> <item name="padding">2dp</item> <item name="text_color">@color/colorPrimaryDark</item> <item name="text_content">text from AppTheme refrence</item> </style> <style name="CustomizeStyleInActivityTheme"> <item name="text_size">10sp</item> <item name="padding">2dp</item> <item name="text_color">@color/colorPrimaryDark</item> <item name="text_content">text from ActivityTheme refrence</item> </style> <style name="CustomStyle"> <item name="text_size">12sp</item> <item name="text_color">#0f0</item> <item name="text_content">text form Style</item> <item name="padding">3dp</item> </style> <style name="DefaultCustomizeStyle"> <item name="text_content">text form DefaultCustomizeStyle</item> <item name="padding">4dp</item> <!--<item name="text_color">#7ff</item>--> </style> <style name="DefaultCustomizeStyle_Notext"> <item name="padding">4dp</item> </style></resources>
字符串在res/values/strings.xml中有定义
<resources> <string name="app_name">017_CustomView</string> <string name="action_settings">Settings</string> <string name="create_by_java">I am created by Java Code</string> <string name="from_App_theme">text from AppTheme</string> <string name="from_Activity_theme">text from ActivityTheme</string> <string name="from_Activity_theme_noCustomizeStyle">text from ActivityTheme with noCustomizeStyle </string></resources>
4.2.2下面我们再来更改下CustomTextView.java文件
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.antex.customview;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Color;import android.graphics.Rect;import android.graphics.Typeface;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.Log;import android.widget.TextView;public class CustomTextView extends TextView { private static final String TAG = CustomTextView.class.getSimpleName(); private String default_namespace = "http://schemas.android.com/apk/res/android"; private String namespace = "http://schemas.android.com/apk/res-auto"; public CustomTextView(Context context) { super(context); Log.d(TAG, "CustomTextView.CustomTextView1"); } public CustomTextView(Context context, AttributeSet attrs) { super(context, attrs); Log.d(TAG, "CustomTextView.CustomTextView2"); init(context, attrs, R.attr.CustomizeStyle, R.style.DefaultCustomizeStyle); } public CustomTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); Log.d(TAG, "CustomTextView.CustomTextView3"); init(context, attrs, defStyle, 0); } public CustomTextView(Context context, AttributeSet attrs, int defStyle, int defStyleRes) { super(context, attrs, defStyle, defStyleRes); Log.d(TAG, "CustomTextView.CustomTextView4"); init(context, attrs, defStyle, defStyleRes); } public void init(Context context, AttributeSet attrs, int defStyle, int defStyleRes) { if (attrs != null) { try { int id = attrs.getAttributeResourceValue(default_namespace, "id", 0); switch (id) { case R.id.textview2: //defStyle=0 and defStyleRes=0 printAttributes(context, attrs); return; case R.id.textview3: defStyle = 0; break; } int textsize, textcolor, padding; String text = "no value"; //获取自定义属性值的三种方法 //方法一 在declare-styleable中定义的属性 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable .CustomTextViewStyle, defStyle, defStyleRes); textsize = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_text_size, 10); textcolor = typedArray.getColor(R.styleable.CustomTextViewStyle_text_color, Color .BLACK); text = typedArray.getString(R.styleable.CustomTextViewStyle_text_content); padding = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_padding, 0); System.out.println("textsize = " + textsize); System.out.println("textcolor = " + textcolor); System.out.println("text = " + text); System.out.println("padding = " + padding); //方法二、自定义属性数组,非常注意,数组中的值一定是从小到大排序,要不然后面会取不到正确的值 int[] CustomTextViewStyle = {R.attr.text_size, R.attr.text_color, R.attr .text_content, R.attr.padding}; TypedArray typedArray2 = context.obtainStyledAttributes(attrs, CustomTextViewStyle, defStyle, defStyleRes); int textsize1 = typedArray2.getDimensionPixelSize(0, 10); int textcolor1 = typedArray2.getColor(1, Color.BLACK); String text1 = typedArray2.getString(2); int padding1 = typedArray2.getDimensionPixelSize(3, 0); System.out.println("textsize1 = " + textsize1); System.out.println("textcolor1 = " + textcolor1); System.out.println("text1 = " + text1); System.out.println("padding1 = " + padding1); //方法三 利用命名空间,根据属性名获取属性值 int textcolor2 = attrs.getAttributeIntValue(namespace, "textcolor", Color.BLACK); //or int resouceId = attrs.getAttributeResourceValue(namespace, "text_color", 0); if (resouceId > 0) { textcolor2 = context.getResources().getColor(resouceId); } else textcolor2 = Color.BLACK; int textsize2 = attrs.getAttributeIntValue(namespace, "text_size", 10); String text2 = attrs.getAttributeValue(namespace, "text_content"); int padding2 = attrs.getAttributeIntValue(namespace, "padding", 0); System.out.println("textsize2 = " + textsize2); System.out.println("textcolor2 = " + textcolor2); System.out.println("text2 = " + text2); System.out.println("padding2 = " + padding2); //namespace is null resouceId = attrs.getAttributeResourceValue(null, "text", 0); if (resouceId > 0) { String null_namespace = context.getResources().getText(resouceId).toString(); System.out.println("null_namespace = " + null_namespace); } setTextColor(textcolor); setTextSize(textsize); setText(text + ""); setPadding(padding, padding, padding, padding); //遍历attrs中所有属性和值 for (int i = 0, m = attrs.getAttributeCount(); i < m; i++) { System.out.println("AttributeName = " + attrs.getAttributeName(i) + ", " + "AttributeValue = " + attrs.getAttributeValue(i)); } //介绍getAttributeNameResource(int index)方法 int[] ids = new int[attrs.getAttributeCount()]; for (int i = 0; i < attrs.getAttributeCount(); i++) { ids[i] = attrs.getAttributeNameResource(i); //System.out.println("ids[" + i + "] = 0x" + Integer.toHexString(ids[i])); } TypedArray a = context.obtainStyledAttributes(attrs, ids, defStyle, 0); for (int i = 0; i < attrs.getAttributeCount(); i++) { String attrName = attrs.getAttributeName(i); if (attrName == null) continue; System.out.println("attrName = " + attrName + ",attrValue = " + a.getString(i)); } a.recycle(); typedArray.recycle(); typedArray2.recycle(); } catch (Exception e) { e.printStackTrace(); } } } /** * 介绍TypedArray使用方法 * 获取 attr中formate 十种类型属性值 * float,integer,boolean,fraction,string,dimension,color,reference,enum,flag * <p/> * * @param context 上下文环境 * @param attrs 属性集合 */ private void printAttributes(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable .CustomTextViewStyle, 0, 0); System.out.println("typedArray.getChangingConfigurations() = " + Integer.toHexString (typedArray.getChangingConfigurations())); float float_value = typedArray.getFloat(R.styleable.CustomTextViewStyle_float_value, 0f); int integer_value = typedArray.getInteger(R.styleable.CustomTextViewStyle_integer_value, 0); boolean boolean_value = typedArray.getBoolean(R.styleable .CustomTextViewStyle_boolean_value, false); //public float getFraction (int index, int base, int pbase, float defValue) // 如果值为10% 则 fraction_value=10%*base //如果值格式为10%p,则fraction_value=10%*pbase float fraction_value = typedArray.getFraction(R.styleable .CustomTextViewStyle_fraction_value, 1, 1, 0); String string_value = typedArray.getString(R.styleable.CustomTextViewStyle_string_value); //获取像素值,浮点数 eg:27.5625 float dimension_value_float = typedArray.getDimension(R.styleable .CustomTextViewStyle_dimension_value, 0f); //将取得浮点像素值四舍五入 eg:28 int dimension_value = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_dimension_value, 0); //将取得浮点像素值直接截取整数部分 eg:27 int dimension_value_offset_ = typedArray.getDimensionPixelOffset(R.styleable .CustomTextViewStyle_dimension_value, 0); int color_value = typedArray.getColor(R.styleable.CustomTextViewStyle_color_value, 0); int reference_drawable_value = typedArray.getResourceId(R.styleable .CustomTextViewStyle_reference_drawable_value, 0); int reference_array_value = typedArray.getResourceId(R.styleable .CustomTextViewStyle_reference_array_value, 0); int enum_value = typedArray.getInt(R.styleable.CustomTextViewStyle_enum_value, -1); int flag_value = typedArray.getInt(R.styleable.CustomTextViewStyle_flag_value, -1); System.out.println("float_value = [" + float_value + "], integer_value = [" + integer_value + "], " + "boolean_value = [" + boolean_value + "], fraction_value = [" + fraction_value + "], string_value = [" + string_value + "], dimension_value = [" + dimension_value + "], color_value = [" + color_value + "], " + "reference_drawable_value =" + " [0x" + Integer.toHexString(reference_drawable_value) + "], enum_value = [" + enum_value + "], " + "flag_value1 = [" + flag_value + "]"); //后期数据处理,设置左边图片 Drawable drawable; drawable = typedArray.getDrawable(R.styleable.CustomTextViewStyle_reference_drawable_value); //or drawable = context.getDrawable(reference_drawable_value); drawable.setBounds(new Rect(0, 0, 50, 50)); setCompoundDrawables(drawable, null, null, null); //设置文字是否大写,斜体 if (flag_value >= 0) { Typeface typeface = getTypeface(); setTypeface(Typeface.defaultFromStyle(flag_value)); } //其他方法getTextArray CharSequence[] arrays; arrays = typedArray.getTextArray(R.styleable.CustomTextViewStyle_reference_array_value); //or arrays = context.getResources().getTextArray(reference_array_value); for (int i = 0; i < arrays.length; i++) { System.out.println("arrays[" + i + "] = " + arrays[i]); } //遍历TypedArray for (int i = 0, m = typedArray.getIndexCount(); i < m; i++) { System.out.println("typedArray" + i + " type= " + typedArray.getType(i) + " value=" + typedArray.getString(i)); } //defStyle=0,defStyleRes =0 int textsize = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_text_size, 10); int textcolor = typedArray.getColor(R.styleable.CustomTextViewStyle_text_color, Color .BLACK); String text = typedArray.getString(R.styleable.CustomTextViewStyle_text_content); int padding = typedArray.getDimensionPixelSize(R.styleable.CustomTextViewStyle_padding, 0); setTextColor(textcolor); setTextSize(textsize); setText(text); setPadding(padding, padding, padding, padding); typedArray.recycle(); }}
4.2.3.1 主要方法介绍
1.使用系统生成的int[] attrs数组R.styleable.CustomTextViewStyle,获取属性值时调用系统生成的数组下标索引
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable .CustomTextViewStyle, defStyle, defStyleRes); textsize = typedArray.getDimensionPixelSize(R.styleable .CustomTextViewStyle_text_size, 10);
2.自己封装int[] attrs数组,由于数组是自己定义的,所以获取什么属性用什么数组下标索引自己是清楚的
陷阱:这个数组并不是你想怎么组装就怎么组装的,数组里面值要从小到大排列,至于大小,到R文件attr类中查看
int[] CustomTextViewStyle = {R.attr.text_size, R.attr.text_color, R.attr .text_content, R.attr.padding}; TypedArray typedArray2 = context.obtainStyledAttributes(attrs, CustomTextViewStyle, defStyle, defStyleRes); int textsize1 = typedArray2.getDimensionPixelSize(0, 10);
3.使用命名空间获取属性
private String namespace = "http://schemas.android.com/apk/res-auto";int textcolor2 = attrs.getAttributeIntValue(namespace, "textcolor", Color.BLACK);//还有另外一种写法,利用getAttributeResourceValue()获取该属性值是否在系统中定义了int resouceId = attrs.getAttributeResourceValue(namespace, "text_color", 0);if (resouceId > 0) { textcolor2 = context.getResources().getColor(resouceId);} else textcolor2 = Color.BLACK;
如果没有使用命名空间,namespace可以置为null
<com.antex.customview.CustomTextView android:id="@+id/textview0" text="@string/app_name" …… />//namespace is nullresouceId = attrs.getAttributeResourceValue(null, "text", 0);if (resouceId > 0) { String null_namespace = context.getResources().getText(resouceId).toString(); System.out.println("null_namespace = " + null_namespace);}
4.2.3 Activity代码
src/java/CustomViewActivityFragment.java
package com.antex.customview;import android.content.Intent;import android.os.Bundle;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.RadioButton;import android.widget.RadioGroup;/** * A placeholder fragment containing a simple view. */public class CustomViewActivityFragment extends Fragment { private int Themes[] = {R.style .AppTheme_WithCustomizeStyle_Activity_WithValues_withCustomizeStyle, R.style .AppTheme_WithCustomizeStyle_Activity_WithValues, R.style .AppTheme_WithCustomizeStyle_Activity_NoValues, R.style .AppTheme_NoCustomizeStyle_Activity_NoValues}; public CustomViewActivityFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Intent intent = getActivity().getIntent(); int checkedID = intent.getIntExtra("checkedID", 0); getActivity().setTheme(Themes[checkedID]); View view = inflater.inflate(R.layout.fragment_custom_view, container, false); LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.linearLayout); CustomTextView customTextView1 = new CustomTextView(getActivity()); customTextView1.setText("New CustomTextView"); linearLayout.addView(customTextView1, 0, new ViewGroup.LayoutParams(ViewGroup .LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); final RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.radiaGroup); ((RadioButton) radioGroup.getChildAt(checkedID)).setChecked(true); radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { int id = 0; switch (checkedId) { case R.id.rb1: id = 0; break; case R.id.rb2: id = 1; break; case R.id.rb3: id = 2; break; case R.id.rb4: id = 3; break; default: break; } startActivity(new Intent(getActivity(), CustomViewActivity.class).putExtra ("checkedID", id)); getActivity().finish(); } }); return view; }}
4.2.4演示效果:
4.2.5效果解释
页面下有四个theme
总共6个TextView
第一个是在java文件中通过new生成的
第二个是在XML中直接指定的,并且也指定了style
第三个是设置了Style的
这三个无论是在哪个theme下显示效果都是一样的
说明了两点
1.在XML中指定值优先级>在style中指定值
2.在style中指定值的优先级>大于通过defStyleAttr,
和defStyleRes和在theme中指定
我们主要关注下下面三个TextView
第四个TextView:
defStyleAttr=0 && defStyleRes=0
3.不论在theme中是否引用defStyleAttr,是否指定defStyleRes,都是不起作用的
选择前两个theme时,Activity Theme中有属性值,显示的是Activity Theme中的值“text from ActivityTheme”
选择后两个theme时,Activity Theme中没有有属性值,显示的是Application Theme中的值“text from AppTheme”
说明
4.在Activity Theme指定值的优先级>在Application Theme中指定的值
第五个TextView:
defStyleAttr=0 defStyleRes!=0
“DefaultCustomizeStyle”中有指定文字,但没有指定文字颜色
四中情况下都是显示的“text form DefaultCustomizeStyle”,
但是选择前两个theme时,显示的是Activity Theme中颜色
选择后两个theme时,显示的是Application Theme中颜色
说明
5.defStyleRes>Activity Theme指定值的优先级>在Application Theme中指定的值
第六个TextView:
defStyleAttr!=0 && defStyleRes!=0
6.Activity Theme中指定 defStyleAttr>Application Theme中指定 defStyleAttr
7.Application Theme中指定 defStyleAttr>指定defStyleRes
优先级总结:
在XML中直接指定>在style中指定值>在Activity theme中指定了defStyleAttr(>0)>在Application theme中指定了defStyleAttr(>0)>指定了defStyleRes(>0)>在Activity theme中指定的值>在Application theme中指定的值
开发工具:Android Studio1.5
SDK: Android 6.0
API 23
代码下载:017_CustomView_AttributeSet.zip
- 安卓开发学习之017 自定义控件之属性获取
- 安卓开发之自定义控件实现画板
- 安卓开发之自定义粒子旋转动画加载控件
- 安卓开发之使用PathMeasure自定义加载动画控件
- 安卓开发之自定义控件实现MaterialEditText
- 安卓开发之自定义控件实现MaterialEditText
- 安卓学习笔记之自定义组合控件
- #安卓杂记(七):自定义控件及属性获取
- 安卓自定义控件,自定义控件属性
- 安卓开发学习之018 创建复合控件
- 安卓自定义控件之饼图
- 安卓自定义控件之仪表盘
- 安卓自定义控件之折线图
- 安卓开发学习之019 创建自定义视图
- 自定义控件之自定义属性
- 菜鸟的安卓实习之路---自定义控件的属性
- Android开发技巧——自定义控件之自定义属性
- 安卓学习之控件学习笔记
- JSON使用OnSerializing,OnSerialized,OnDeserializing,OnDeserialized
- 运行BP神经网络预测误差大
- spring中如何给集合元素注入值(第四篇)
- 学习maven的使用,看到一篇很实用的入门教程(菜鸟级入门)
- 周鸿祎:混日子,会让你失去竞争力
- 安卓开发学习之017 自定义控件之属性获取
- 有哪些问题是找工作的才会考虑得??
- 通过快速枚举的方法查找文件
- Java:一些访问资源的技巧
- Android的Listview的ListAdapter关于View的经典写法
- 对话框学习经验摘记
- JBPM4.4:流程定义语言和活动、事件
- Unrecognized Windows Sockets error: 0: JVM_Bind 异常解决办法
- JAVA中的堆和栈