如何在Android中以编程方式加载布局XML文件?

10

我已经制作了一个布局(比如说my_layout.xml),其中包括两个其他的XML布局文件,分别是some_layout.xmlanother_layout.xml。使用setContentView(R.layout.my_layout)来绘制my_layout.xml

现在我有一个ID为some_checkbox的复选框,它被定义在some_layout.xml内,我想使用setOnCheckedChangeListener()给这个复选框设置一个OnCheckedChangeListener,就像这样:

CheckBox cb = (CheckBox) findViewById(R.id.some_checkbox);
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    ...
});

现在抛出了 NullPointerException 异常,因为 cbnull。我想这是因为包含 some_checkbox(即 some_layout)的布局没有使用 setContentView(R.layout.some_layout) 加载。

  • 问题1:为什么会返回 nullsome_layout 确实可见。
  • 问题2:如何“加载”some_layout,以便可以像在上面的代码片段中尝试的那样将其捕获到变量中?

更新

我终于解决了它,使用了 stealthjong 建议的以下内容:

一个解决方案可能是初始化 checkedChangeListener,向您的可扩展列表视图添加侦听器,并在打开可扩展列表视图的子项时检查您的 Checkbox 是否为膨胀的子项之一,如果是,则添加 checkedchangeListener

我创建了一个名为 setCheckedChangeListenerToElement(int resourceId, OnCheckedChangeListener listener) 的方法,它保存了给定的 resourceId(要附加侦听器的元素的ID)和给定的 listener。一旦 inflater 调用方法 getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent),就可以检索到 View。然后,在该 View 上,可以调用 findViewById(int resourceId),其中 resourceId 是复选框的 ID。


这当然不正常。抱歉,也许是个愚蠢的问题,但是你尝试过清理项目吗? - rciovati
我尝试了,但它没有起作用。 - MC Emperor
你尝试过先从根视图中查找 some_layout,然后再从该对象中搜索复选框吗? - Joel Bodega
2个回答

23

有两种方法可以实现这个。

第一种是通过XML添加子布局:

1. XML方法

my_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <include
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        layout="@layout/child_layout1" >
    </include>

    <include
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        layout="@layout/child_layout2" />

</LinearLayout>

child_layout1child_layout2只是另外两个布局,第二个布局包含一个带有id为mbuttonButton

您的应用程序入口应该像这样:

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);
        View v = findViewById(R.id.mbutton);
        System.out.println(v == null);
        System.out.println(v.getClass().getName());
    }   
}

这使我得到了一个false和一个android.widget.Button,正如我所预料的。

2. 编程方法

另一种方法是编程方法,考虑到你是这样描述它的,我猜测这就是你做的事情(或者至少尝试过):

noinclude_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/inclusionlayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </RelativeLayout>

</LinearLayout>

还有一个稍微大一点的应用程序入口点:

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.noinclude_layout);
        ViewGroup inclusionViewGroup = (ViewGroup)findViewById(R.id.inclusionlayout);

        View child1 = LayoutInflater.from(this).inflate(
                R.layout.child_layout1, null); 
        View child2 = LayoutInflater.from(this).inflate(
                R.layout.child_layout2, null);
        inclusionViewGroup.addView(child1);
        inclusionViewGroup.addView(child2);

        View v = findViewById(R.id.mbutton);
        System.out.println(v == null);
        System.out.println(v.getClass().getName());
    }   
}

这也会让我得到一个false和一个android.widget.Button

任何一种解决方案都应该可以正常工作。

更新

你的expandableListView是问题所在,因为 childLayout 直到您打开/展开部分时才被填充(查看下面的代码片段以检查当前视图树)。

其中一种解决方案可能是初始化checkedChangeListener,将监听器添加到 expandable listview 中,当展开可扩展列表视图的子项时,检查您的 Checkbox 是否是已填充的子项之一,如果是,则添加checkedchangeListener

可能更直接的方法是:

<CheckBox
    ...
    android:onClick="checkclicked" />

在您的Activity中,添加方法public void checkclicked(View view){ ... }

ViewTree打印机

private void printFullTree() {
    printTree(this.getWindow().getDecorView(),0);
}

private void printTree(View view, int indent) {
    System.out.print(indent(indent) + view.getClass().getName() + "; " + view.getId());
    if (view instanceof ViewGroup) {
        ViewGroup vg = (ViewGroup)view;
        System.out.print("; children = " + vg.getChildCount() + "\n");
        for (int i = 0; i< vg.getChildCount(); i++) {
            printTree(vg.getChildAt(i), indent++);
        }
    }
    else
        System.out.print("\n");
}

private String indent(int indent) {
    String result = "";
    for (int i = 0; i < indent; i++) {
        result += "  ";
    }
    return result;
}

9
如果在my_layout.xml中使用include标记包含了some_layout.xml,如下所示:
<include layout="@layout/some_layout" android:id="@+id/someLayoutId" />

那么您可以按照以下步骤操作: -
View someLayoutView = findViewById(R.id.someLayoutId);
CheckBox cb = (CheckBox) someLayoutView.findViewById(R.id.some_checkbox);

如果您以编程方式膨胀了一些_layout.xml,例如:-
View someLayoutView = LayoutInflater.from(mContext).inflate(
                    R.layout.some_layout, null);

然后您仍然可以按照上述方法进行操作:-
CheckBox cb = (CheckBox) someLayoutView.findViewById(R.id.some_checkbox);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接