自定义view时使用xml传递参数-设定TextView中图片大小

来源:互联网 发布:xilinx for mac 编辑:程序博客网 时间:2024/06/06 12:27

当给的widget不能满足使用的时候就需要自定义。用xml配置view十分方便。如果我们希望通过xml向view中传递参数,就得多写点东西。下面写的例子是对TextView的一个扩展。TextView提供了设置四个方向图片的功能,但是无法设置图片的大小就不太好了。本文实现了一个新的类TextViewPlus,对TextView进行扩展,让其能够在xml中配置图片大小。

改变图片大小不能在xml中做,但是可以在java代码中做。先取得文本周围四个方向的图片Drawable[],然后分别调用drawable.setBounds()设置大小,最后再放回TextView中。然后问题就出在怎么让类读取xml中信息上了。

代码一共分为3部分:

1. main.xml布局文件; 2. TextViewPlus类; 3. attrs.xml文件,用于让系统识别自定义属性。构建顺序应该是attrs.xml -> TextViewPlus -> main.xml

配置文件attrs.xml

<?xml version="1.0" encoding="UTF-8"?><resources>    <declare-styleable name="TextViewPlus">        <attr name="left_height" format="dimension" />        <attr name="left_width" format="dimension" />        <attr name="right_height" format="dimension" />        <attr name="right_width" format="dimension" />        <attr name="top_height" format="dimension" />        <attr name="top_width" format="dimension" />        <attr name="bottom_height" format="dimension" />        <attr name="bottom_width" format="dimension" />    </declare-styleable></resources>
解释:attrs.xml放在res/values中。第4行的name需要指定使用参数的类。第5~12行写的需要在布局文件中设置的参数。name是名称,format是数据类型。系统会自动生成R文件中的变量。

类TextViewPlus

/** * 添加可以设置drawable大小的功能 *  * @author Daniel * @version 创建时间: Jul 26, 2012 5:28:59 PM * */public class TextViewPlus extends TextView {// 需要从xml中读取的各个方向图片的宽和高private int leftHeight = -1;private int leftWidth = -1;private int rightHeight = -1;private int rightWidth = -1;private int topHeight = -1;private int topWidth = -1;private int bottomHeight = -1;private int bottomWidth = -1;public TextViewPlus(Context context) {super(context);}public TextViewPlus(Context context, AttributeSet attrs) {super(context, attrs);// super一定要在我们的代码之前配置文件init(context, attrs, 0);}public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// super一定要在我们的代码之前配置文件init(context, attrs, defStyle);}/** * 初始化读取参数 * */private void init(Context context, AttributeSet attrs, int defStyle) {// TypeArray中含有我们需要使用的参数TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.TextViewPlus, defStyle, 0);if (a != null) {// 获得参数个数int count = a.getIndexCount();int index = 0;// 遍历参数。先将index从TypedArray中读出来,// 得到的这个index对应于attrs.xml中设置的参数名称在R中编译得到的数// 这里会得到各个方向的宽和高for (int i = 0; i < count; i++) {index = a.getIndex(i);switch (index) {case R.styleable.TextViewPlus_bottom_height:bottomHeight = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_bottom_width:bottomWidth = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_left_height:leftHeight = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_left_width:leftWidth = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_right_height:rightHeight = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_right_width:rightWidth = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_top_height:topHeight = a.getDimensionPixelSize(index, -1);break;case R.styleable.TextViewPlus_top_width:topWidth = a.getDimensionPixelSize(index, -1);break;}}// 获取各个方向的图片,按照:左-上-右-下 的顺序存于数组中Drawable[] drawables = getCompoundDrawables();int dir = 0;// 0-left; 1-top; 2-right; 3-bottom;for (Drawable drawable : drawables) {// 设定图片大小setImageSize(drawable, dir++);}// 将图片放回到TextView中setCompoundDrawables(drawables[0], drawables[1], drawables[2],drawables[3]);}}/** * 设定图片的大小 * */private void setImageSize(Drawable d, int dir) {if (d == null) {return;}int height = -1;int width = -1;// 根据方向给宽和高赋值switch (dir) {case 0:// leftheight = leftHeight;width = leftWidth;break;case 1:// topheight = topHeight;width = topWidth;break;case 2:// rightheight = rightHeight;width = rightWidth;break;case 3:// bottomheight = bottomHeight;width = bottomWidth;break;}// 如果有某个方向的宽或者高没有设定值,则不去设定图片大小if (width != -1 && height != -1) {d.setBounds(0, 0, width, height);}}}

解释:那个读取TypedArray是主要部分。你可以把TypedArray当成一个Map<Integer key, Object value>。通过遍历key,来获得各个value。而这个key的值是写在R.stylable中的。而value需要用getDimensionPixelSize()等方法读取,这个和调用数据库从cursor中读取数据有点像。


布局文件main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:myview="http://schemas.android.com/apk/res/org.daniel.android.test"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <org.daniel.android.test.TextViewPlus        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:drawableBottom="@drawable/ic_launcher"        android:drawableLeft="@drawable/ic_launcher"        android:drawableRight="@drawable/ic_launcher"        android:drawableTop="@drawable/ic_launcher"        android:text="here is a test"        myview:left_height="30dp"        myview:left_width="30dp" /></LinearLayout>

解释:主要注意第3行和第17~18行。第3行用于声明我需要使用这个项目自己定义的属性。第17~18行就是使用属性了。这个属性就是在attrs.xml中定义的属性。3行和17~18行的myview是对应的,这个名字可以任意换,只要不是关键词和同时对应就行。