目录
版权声明:本文为博主原创文章,未经博主允许不得转载。
1.前言
写这篇博客主要是为了我的下一篇博客做准备,由于下一篇博客里面用到了自定义属性,我想在这里还是给大家讲解以下比较好。同时也用到了自定义view的其它知识点,但是都比较简单。这里就着重介绍一下自定义View属性。
编写自定义View主要有以下几个步骤:
1)自定义一个MyView需要继承View类
2)在Values文件夹下面创建attrs.xml文件
3)在布局文件中使用自定义的属性,需要注意前面的命名空间
4)在MyView的构造方法中获取这些属性。
光说不练假把式,下面我们就通过代码的方式来介绍自定义View属性的使用。
2.实例
通过代码可以更好的说明自定义属性的用法
* 自定义View类
public class MyView extends View {
private float textSize;
private int textColor;
public MyView(Context context) {
this(context,null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView);
textSize = typedArray.getDimension(R.styleable.VoteView_myTextSize, -1);
textColor = typedArray.getColor(R.styleable.VoteView_myTextColor, -1);
System.out.println("textSize:"+textSize+"textColor:"+textColor);
typedArray.recycle();
}
}
这里需要注意的一点是必须在最后调用TypedArray的recycle()方法,用来释放资源
自定义View属性
<declare-styleable name="MyView"> <attr name="MySize" format="dimension" /> <attr name = "MyColor" format = "color" />
布局文件
3.在XML文件中导入属性集的两种方法
3.1 方法一
首先在根布局上加上
xmlns:shi ="http://schemas.android.com/apk/res/com.shi.mychat2"
这里有两点需要注意的地方
1.xmlns:shi,这里的shi是自定义的,你想定义成什么就可以定义成什么。但要注意的是,下面访问你定义的XML控件属性时,就是通过这个标识符访问的。比如我们这里定义成shi;那我们下面对应的访问自定义:
shi:MySize="@dimen/tensp"
2、最后的:com.shi.mychat2,是AndroidManifest.xml中的包名。即AndroidManifest.xml中package字段对应的值,如下所示:
3.2 方法二
另一种自动导入自定义属性集的方式要相对简单,要根布局控件上添加:
xmlns:shi="http://schemas.android.com/apk/res-auto"
这里面的含义和上面的一样。
读到这里我们应该明白,为什么我们没有导入属性集也能使用自定义属性,那是因为我们用到的Support中的控件也用到了自定义属性,已经事先导入过了 xmlns:app=”http://schemas.android.com/apk/res-auto”。如果没有用到Support包中的控件还需要自己手动的导入。
4.获取定义属性的所有方法
使用代码获取某个属性用户所定义的值,主要是使用TypedArray类,这个类担供了所有的获取某个属性值的方法,
typedArray.getInt(int index, float defValue);
typedArray.getDimension(int index, float defValue);
typedArray.getBoolean(int index, float defValue);
typedArray.getColor(int index, float defValue);
typedArray.getString(int index)
typedArray.getDrawable(int index);
typedArray.getResources();
5.declare-styleable标签其它属性用法
1、 reference:参考某一资源ID。
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "background" format = "reference" />
</declare-styleable>
(2)属性使用:
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID"/>
2. color:颜色值。
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "textColor" format = "color" />
</declare-styleable>
(2)属性使用:
<TextView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:textColor = "#00FF00"/>
3. boolean:布尔值。
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "focusable" format = "boolean" />
</declare-styleable>
(2)属性使用:
<Button
android:layout_width = "42dip"
android:layout_height = "42dip"
android:focusable = "true"/>
4. dimension:尺寸值。
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "layout_width" format = "dimension" />
</declare-styleable>
(2)属性使用:
<Button
android:layout_width = "42dip"
android:layout_height = "42dip"/>
5. float:浮点值。
(1)属性定义:
<declare-styleable name = "AlphaAnimation">
<attr name = "fromAlpha" format = "float" />
<attr name = "toAlpha" format = "float" />
</declare-styleable>
(2)属性使用:
<alpha
android:fromAlpha = "1.0"
android:toAlpha = "0.7"/>
6. integer:整型值。
(1)属性定义:
<declare-styleable name = "AnimatedRotateDrawable">
<attr name = "visible" />
<attr name = "frameDuration" format="integer" />
<attr name = "framesCount" format="integer" />
<attr name = "pivotX" />
<attr name = "pivotY" />
<attr name = "drawable" />
</declare-styleable>
(2)属性使用:
<animated-rotate
xmlns:android = "http://schemas.android.com/apk/res/android"
android:drawable = "@drawable/图片ID"
android:pivotX = "50%"
android:pivotY = "50%"
android:framesCount = "12"
android:frameDuration = "100"/>
7. string:字符串。
(1)属性定义:
<declare-styleable name = "MapView">
<attr name = "apiKey" format = "string" />
</declare-styleable>
(2)属性使用:
<com.google.android.maps.MapView
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" />
- fraction:百分数。
(1)属性定义:
<declare-styleable name="RotateDrawable">
<attr name = "visible" />
<attr name = "fromDegrees" format = "float" />
<attr name = "toDegrees" format = "float" />
<attr name = "pivotX" format = "fraction" />
<attr name = "pivotY" format = "fraction" />
<attr name = "drawable" />
</declare-styleable>
(2)属性使用:
<rotate
xmlns:android = "http://schemas.android.com/apk/res/android"
android:interpolator = "@anim/动画ID"
android:fromDegrees = "0"
android:toDegrees = "360"
android:pivotX = "200%"
android:pivotY = "300%"
android:duration = "5000"
android:repeatMode = "restart"
android:repeatCount = "infinite"/>
9. enum:枚举值。
(1)属性定义:
<declare-styleable name="名称">
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
</declare-styleable>
(2)属性使用:
<LinearLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent">
</LinearLayout>
10. flag:位或运算。
(1)属性定义:
<declare-styleable name="名称">
<attr name="windowSoftInputMode">
<flag name = "stateUnspecified" value = "0" />
<flag name = "stateUnchanged" value = "1" />
<flag name = "stateHidden" value = "2" />
<flag name = "stateAlwaysHidden" value = "3" />
<flag name = "stateVisible" value = "4" />
<flag name = "stateAlwaysVisible" value = "5" />
<flag name = "adjustUnspecified" value = "0x00" />
<flag name = "adjustResize" value = "0x10" />
<flag name = "adjustPan" value = "0x20" />
<flag name = "adjustNothing" value = "0x30" />
</attr>
</declare-styleable>
(2)属性使用:
<activity
android:name = ".StyleAndThemeActivity"
android:label = "@string/app_name"
android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
特别要注意:
属性定义时可以指定多种类型值。
(1)属性定义:
<declare-styleable name = "名称">
<attr name = "background" format = "reference|color" />
</declare-styleable>
(2)属性使用:
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/图片ID|#00FF00"/>
6 AttributeSet与TypedArray 详解
构造方法中的有个参数叫做AttributeSet(eg: MyView(Context context, AttributeSet attrs) )这个参数看名字就知道包含的是参数的集合,那么我能不能通过它去获取我的自定义属性呢?
首先AttributeSet中的确保存的是该View声明的所有的属性,并且外面的确可以通过它去获取(自定义的)属性,怎么做呢?
其实看下AttributeSet的方法就明白了,下面看代码。
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
int count = attrs.getAttributeCount();
for (int i = 0; i < count; i++) {
String attrName = attrs.getAttributeName(i);
String attrVal = attrs.getAttributeValue(i);
Log.e(TAG, "attrName = " + attrName + " , attrVal = " + attrVal);
}
}
布局
<com.shi.mychat2.customview.MyView
android:layout_width="100dp"
shi:MySize="10dp"
app:MyColor="#fff"
android:layout_height="100dp" />
输出:
10-15 17:06:42.518 5870-5870/? I/System.out: attrName = layout_width , attrVal = 100.0dip
10-15 17:06:42.518 5870-5870/? I/System.out: attrName = layout_height , attrVal = 100.0dip
10-15 17:06:42.518 5870-5870/? I/System.out: attrName = MyColor , attrVal = #ffffffff
10-15 17:06:42.518 5870-5870/? I/System.out: attrName = MySize , attrVal = 10.0dip
通过AttributeSet可以获得布局文件中定义的所有属性的key和value(还有一些方法,自己去尝试),那么是不是说TypedArray这个类是否可以不用了呢,答案是否定的。
现在关注下一个问题:
TypedArray是什么鬼?从哪冒出来的,就要我去使用?
我们简单修改下,布局文件中的MyView的属性。
<com.shi.mychat2.customview.MyView
android:layout_width="100dp"
shi:MySize="@dimen/tensp"
app:MyColor="@color/F8f8f8"
android:layout_height="100dp" />
现在再次运行的结果是:
10-15 17:03:18.148 5470-5470/? I/System.out: attrName = layout_width , attrVal = 100.0dip
10-15 17:03:18.148 5470-5470/? I/System.out: attrName = layout_height , attrVal = 100.0dip
10-15 17:03:18.148 5470-5470/? I/System.out: attrName = MyColor , attrVal = @2131034112
10-15 17:03:18.148 5470-5470/? I/System.out: attrName = MySize , attrVal = @2131099845
use typedarray
10-15 17:06:42.518 5870-5870/? I/System.out: attrName = MyColor , attrVal = #ffffffff
发现了什么?通过AttributeSet获取的值,如果是引用都变成了@+数字的字符串。你说,这玩意你能看懂么?那么你看看最后一行使用TypedArray获取的值,是不是瞬间明白了什么。
TypedArray其实是用来简化我们的工作的,比如上例,如果布局中的属性的值是引用类型(比如:@dimen/dp100),如果使用AttributeSet去获得最终的像素值,那么需要第一步拿到id,第二步再去解析id。而TypedArray正是帮我们简化了这个过程。
贴一下:如果通过AttributeSet获取最终的像素值的过程:
int widthDimensionId = attrs.getAttributeResourceValue(0, -1);
Log.e(TAG, "layout_width= "+getResources().getDimension(widthDimensionId));