我如何声明一个Android UI元素使用XML?


当前回答

Android开发者指南中有一个章节叫做构建自定义组件。不幸的是,关于XML属性的讨论只涉及在布局文件中声明控件,而没有实际处理类初始化中的值。具体步骤如下:

1. 在值\attrs.xml中声明属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomView">
        <attr name="android:text"/>
        <attr name="android:textColor"/>            
        <attr name="extraInformation" format="string" />
    </declare-styleable>
</resources>

注意在declare- stylesable标记中使用了非限定名称。像extrinformation这样的非标准android属性需要声明它们的类型。在父类中声明的标记将在子类中可用,而无需重新声明。

2. 创建构造函数

由于有两个构造函数使用AttributeSet进行初始化,因此可以方便地创建一个单独的初始化方法供构造函数调用。

private void init(AttributeSet attrs) { 
    TypedArray a=getContext().obtainStyledAttributes(
         attrs,
         R.styleable.MyCustomView);

    //Use a
    Log.i("test",a.getString(
         R.styleable.MyCustomView_android_text));
    Log.i("test",""+a.getColor(
         R.styleable.MyCustomView_android_textColor, Color.BLACK));
    Log.i("test",a.getString(
         R.styleable.MyCustomView_extraInformation));

    //Don't forget this
    a.recycle();
}

R.styleable.MyCustomView is an autogenerated int[] resource where each element is the ID of an attribute. Attributes are generated for each property in the XML by appending the attribute name to the element name. For example, R.styleable.MyCustomView_android_text contains the android_text attribute for MyCustomView. Attributes can then be retrieved from the TypedArray using various get functions. If the attribute is not defined in the defined in the XML, then null is returned. Except, of course, if the return type is a primitive, in which case the second argument is returned.

如果不想检索所有属性,可以手动创建该数组。标准android属性的ID包含在android. r中。这个项目的属性在R.attr中。

int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};

请注意,你不应该在android.R中使用任何东西。可样式的,根据这个线程,它可能会在未来改变。它仍然在文档中被认为在一个地方查看所有这些常量是有用的。

3.在布局文件中使用它,例如layout\main.xml

Include the namespace declaration xmlns:app="http://schemas.android.com/apk/res-auto" in the top level xml element. Namespaces provide a method to avoid the conflicts that sometimes occur when different schemas use the same element names (see this article for more info). The URL is simply a manner of uniquely identifying schemas - nothing actually needs to be hosted at that URL. If this doesn't appear to be doing anything, it is because you don't actually need to add the namespace prefix unless you need to resolve a conflict.

<com.mycompany.projectname.MyCustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/transparent"
    android:text="Test text"
    android:textColor="#FFFFFF"
    app:extraInformation="My extra information"
/> 

使用完全限定名引用自定义视图。

Android LabelView样本

如果你想要一个完整的例子,看看android标签视图示例。

LabelView.java

 TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
 CharSequences=a.getString(R.styleable.LabelView_text);

attrs.xml

<declare-styleable name="LabelView">
    <attr name="text"format="string"/>
    <attr name="textColor"format="color"/>
    <attr name="textSize"format="dimension"/>
</declare-styleable>

custom_view_1.xml

<com.example.android.apis.view.LabelView
    android:background="@drawable/blue"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    app:text="Blue" app:textSize="20dp"/>

它包含在线性布局中,具有命名空间属性:

链接

StackOverflow线程:为自定义控件检索XML属性 我如何使用obtainStyledAttributes与内部主题的Android 定义自定义属性+支持的属性格式列表

其他回答

非常感谢你的第一个回答。

至于我,我只有一个问题。当我夸大我的观点时,我有一个bug: java.lang.NoSuchMethodException: MyView(上下文,属性)

我通过创建一个新的构造函数来解决这个问题:

public MyView(Context context, AttributeSet attrs) {
     super(context, attrs);
     // some code
}

希望这对你有所帮助!

谷歌似乎更新了它的开发者页面,并在那里增加了各种培训。

其中一个处理自定义视图的创建,可以在这里找到

Android开发者指南中有一个章节叫做构建自定义组件。不幸的是,关于XML属性的讨论只涉及在布局文件中声明控件,而没有实际处理类初始化中的值。具体步骤如下:

1. 在值\attrs.xml中声明属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomView">
        <attr name="android:text"/>
        <attr name="android:textColor"/>            
        <attr name="extraInformation" format="string" />
    </declare-styleable>
</resources>

注意在declare- stylesable标记中使用了非限定名称。像extrinformation这样的非标准android属性需要声明它们的类型。在父类中声明的标记将在子类中可用,而无需重新声明。

2. 创建构造函数

由于有两个构造函数使用AttributeSet进行初始化,因此可以方便地创建一个单独的初始化方法供构造函数调用。

private void init(AttributeSet attrs) { 
    TypedArray a=getContext().obtainStyledAttributes(
         attrs,
         R.styleable.MyCustomView);

    //Use a
    Log.i("test",a.getString(
         R.styleable.MyCustomView_android_text));
    Log.i("test",""+a.getColor(
         R.styleable.MyCustomView_android_textColor, Color.BLACK));
    Log.i("test",a.getString(
         R.styleable.MyCustomView_extraInformation));

    //Don't forget this
    a.recycle();
}

R.styleable.MyCustomView is an autogenerated int[] resource where each element is the ID of an attribute. Attributes are generated for each property in the XML by appending the attribute name to the element name. For example, R.styleable.MyCustomView_android_text contains the android_text attribute for MyCustomView. Attributes can then be retrieved from the TypedArray using various get functions. If the attribute is not defined in the defined in the XML, then null is returned. Except, of course, if the return type is a primitive, in which case the second argument is returned.

如果不想检索所有属性,可以手动创建该数组。标准android属性的ID包含在android. r中。这个项目的属性在R.attr中。

int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};

请注意,你不应该在android.R中使用任何东西。可样式的,根据这个线程,它可能会在未来改变。它仍然在文档中被认为在一个地方查看所有这些常量是有用的。

3.在布局文件中使用它,例如layout\main.xml

Include the namespace declaration xmlns:app="http://schemas.android.com/apk/res-auto" in the top level xml element. Namespaces provide a method to avoid the conflicts that sometimes occur when different schemas use the same element names (see this article for more info). The URL is simply a manner of uniquely identifying schemas - nothing actually needs to be hosted at that URL. If this doesn't appear to be doing anything, it is because you don't actually need to add the namespace prefix unless you need to resolve a conflict.

<com.mycompany.projectname.MyCustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/transparent"
    android:text="Test text"
    android:textColor="#FFFFFF"
    app:extraInformation="My extra information"
/> 

使用完全限定名引用自定义视图。

Android LabelView样本

如果你想要一个完整的例子,看看android标签视图示例。

LabelView.java

 TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
 CharSequences=a.getString(R.styleable.LabelView_text);

attrs.xml

<declare-styleable name="LabelView">
    <attr name="text"format="string"/>
    <attr name="textColor"format="color"/>
    <attr name="textSize"format="dimension"/>
</declare-styleable>

custom_view_1.xml

<com.example.android.apis.view.LabelView
    android:background="@drawable/blue"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    app:text="Blue" app:textSize="20dp"/>

它包含在线性布局中,具有命名空间属性:

链接

StackOverflow线程:为自定义控件检索XML属性 我如何使用obtainStyledAttributes与内部主题的Android 定义自定义属性+支持的属性格式列表

您可以将任何布局文件作为-包含在其他布局文件中

             <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="30dp" >

                <include
                    android:id="@+id/frnd_img_file"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    layout="@layout/include_imagefile"/>

                <include
                    android:id="@+id/frnd_video_file"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    layout="@layout/include_video_lay" />

                <ImageView
                    android:id="@+id/downloadbtn"
                    android:layout_width="30dp"
                    android:layout_height="30dp"
                    android:layout_centerInParent="true"
                    android:src="@drawable/plus"/>
            </RelativeLayout>

这里include标签中的布局文件是同一res文件夹中的其他.xml布局文件。

很好的参考。谢谢! 它的补充:

如果您碰巧包含一个库项目,该库项目为自定义视图声明了自定义属性,那么您必须声明您的项目名称空间,而不是库的名称空间。例如:

假定该库有包"com.example.library. library "。Customview”,工作项目有包“com.example”。customview”,那么:

将不工作(显示错误“错误:在包中没有为属性“newAttr”找到资源标识符? “com.example.library。customview”):

<com.library.CustomView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
        android:id="@+id/myView"
        app:newAttr="value" />

将工作:

<com.library.CustomView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
        android:id="@+id/myView"
        app:newAttr="value" />