9

我制作了一个布局(比如my_layout.xml),它以编程方式包括另外两个 XML 布局文件,比如some_layout.xmlanother_layout.xmlmy_layout.xml是使用setContentView(R.layout.my_layout).

现在我有一个带有 ID 的复选框some_checkbox,它在some_layout.xml中定义,我想给复选框一个OnCheckedChangeListenerusing setOnCheckedChangeListener(),就像这样:

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

但现在 aNullPointerException被抛出,因为cbis null。我猜那是因为包含some_checkbox(即some_layout)的布局未使用setContentView(R.layout.some_layout).

  • 问题一:为什么?为什么返回查找R.id.some_checkbox nullsome_layout真的可见的。
  • 问题 2:我如何“加载” some_layout以便可以捕获some_layout到变量中,就像我在上面的代码片段中尝试的那样?

更新

我终于解决了它,使用以下提示,由stealthjong建议:

一种解决方案可能是初始化checkedChangeListener,向您的可扩展列表视图添加一个侦听器,并在打开可扩展列表视图的子视图时检查您Checkbox是否是膨胀的子视图之一,然后添加checkedchangeListenerif 。

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

4

2 回答 2

24

有两种方法。

首先是通过 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>

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

正如我所怀疑的那样,这使我得到 afalse和 a 。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());
    }   
}

这也使我得到 afalse和 a android.widget.Button

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

更新

expandableListView是问题所在,因为在您实际打开/展开该部分之前, childLayout 不会膨胀(请参阅下面的代码以获取检查当前视图树的一小段代码)。

一种解决方案可能是初始化checkedChangeListener,向您的可扩展列表视图添加一个侦听器,并在打开可扩展列表视图的子视图时检查您Checkbox是否是膨胀的子视图之一,然后添加checkedchangeListenerif 。

一种可能更直接的方法是:

<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;
}
于 2013-04-15T21:21:48.417 回答
10

如果 some_layout.xml 使用 include 标签包含在 my_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);

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

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

然后你仍然可以像上面那样做: -

CheckBox cb = (CheckBox) someLayoutView.findViewById(R.id.some_checkbox);
于 2013-04-15T18:57:18.223 回答