如何要求具有指定ID的视图

时间:2013-12-18 18:05:43

标签: android view

我想编写一个自定义视图,需要一些带有特定id的按钮(能够通过id找到),就像在ListActivity中一样,android.R.id.list必须存在,我该怎么办与我自己的自定义ID相同吗?

我计划在Android lib中重用这个视图用于几个用例,但是所有这些视图都必须声明一些具有特定id的特定视图,以便我可以在lib代码中通过id找到它并对其进行操作以供以后用于使用应用...

2 个答案:

答案 0 :(得分:2)

只需执行ListActivity所做的工作。

检查自定义视图中的ID,如果布局中不存在则抛出异常。

来自ListActivity的

片段资料来源:

 @Override
public void onContentChanged() {
    super.onContentChanged();
    View emptyView = findViewById(com.android.internal.R.id.empty);
    mList = (ListView)findViewById(com.android.internal.R.id.list);
    if (mList == null) {
        throw new RuntimeException(
                "Your content must have a ListView whose id attribute is " +
                "'android.R.id.list'");
    }

答案 1 :(得分:2)

最好的方法是以灵活的方式使用自定义属性。它允许任何id成为必需的id,但它也使用dev工具强制使用有效的id。

声明您的自定义视图可以在attrs.xml文件中使用自定义属性进行样式化,如下所示:

<resources>
    <declare-styleable name="MyView">
        <attr name="required_view_id" format="integer" />
    </declare-styleable>
</resources>

然后,您可以从下面的布局文件中引用该属性。特别注意定义“app”命名空间的标题。您可以为自定义属性命名空间使用任何名称,但在以后定义视图时必须声明它以使用任何自定义属性。请注意MyView上的自定义属性。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <View
        android:id="@+id/the_id_of_the_required_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <com.full.package.to.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:required_view_id="@id/the_id_of_the_required_view" />

</LinearLayout>

现在,您需要确保自定义视图类中存在此视图。您可以要求通过覆盖某些构造函数来设置自定义属性。您还需要在某些时候实际验证所需视图的存在。这是一个粗略的想法:

public class MyView extends View {

    private int mRequiredId;

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        checkForRequiredViewAttr(context, attrs);
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        checkForRequiredViewAttr(context, attrs);
    }

    // Verify that the required id attribute was set
    private void checkForRequiredViewAttr(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.MyView, 0, 0);
        mRequiredId = a.getResourceId(R.styleable.MyView_required_view_id, -1);
        a.recycle();
        if (mRequiredId == -1) {
            throw new RuntimeException("No required view id attribute was set");
        }
    }

    // This allows the custom view to be programmatically instantiated, so long as
    // the required id is manually set before adding it to a layout
    public void setRequiredId(int id) {
        mRequiredId = id;
    }

    // Check for the existence of a view with the required id
    @Override
    protected void onAttachedToWindow() {
        View root = getRootView();
        View requiredView = root.findViewById(mRequiredId);
        if (requiredView == null) {
            throw new RuntimeException(
                    String.format("Cannot find view in layout with id of %s", mRequiredId));
        }
        super.onAttachedToWindow();
    }
}

使用onAttachedToWindow检查所需的视图可能不够用于您的目的。例如,它不会阻止删除所需的视图。在布局中查找视图并不是一种廉价的操作,尤其是对于复杂的布局,因此您不应该经常检查它。