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

时间:2013-04-15 18:49:03

标签: android layout

我制作了一个布局(例如 my_layout.xml ),其中包含两个其他XML布局文件,例如 some_layout.xml 另一个_layout.xml my_layout.xml 是使用setContentView(R.layout.my_layout)绘制的。

现在我有一个标识为some_checkbox的复选框,该复选框在 some_layout.xml 中定义,我想使用OnCheckedChangeListener为复选框setOnCheckedChangeListener() ,就像这样:

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:为什么?为什么返回查找R.id.some_checkbox null some_layout 真的 可见。
  • 问题2:如何“加载” some_layout ,以便将some_layout捕获到变量中,就像我在上面的代码段中尝试过一样?

更新

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

  

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

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

2 个答案:

答案 0 :(得分:20)

这有两种方法。

第一个是通过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只是另外两种布局,第二种布局为Button,ID为mbutton

您的申请表应如下所示:

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());
    }   
}

这就像我怀疑的那样给我一个falseandroid.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());
    }   
}

这也让我falseandroid.widget.Button

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

<强>更新

您的expandableListView是问题,因为在您实际打开/展开该部分之前,childLayout不会被充气(请参阅下面的代码以查看当前viewtree的小段代码)。

一个解决方案可能是初始化checkedChangeListener,为您的可扩展列表视图添加一个监听器,并且当可扩展列表视图的子项打开时,检查您的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;
}

答案 1 :(得分:7)

如果some_layout.xml包含在my_layout.xml中,则使用include标记,例如: -

<include layout="@layout/some_layout" android:id="@+id/someLayoutId" />

然后您可以执行以下操作: -

View someLayoutView = findViewById(R.id.someLayoutId);
CheckBox cb = (CheckBox) someLayoutView.findViewById(R.id.some_checkbox);

如果以编程方式夸大some_layout.xml,例如: -

View someLayoutView = LayoutInflater.from(mContext).inflate(
                    R.layout.some_layout, null);

然后你仍然可以这样做: -

CheckBox cb = (CheckBox) someLayoutView.findViewById(R.id.some_checkbox);