Как программно загрузить XML-файл макета в Android?

я сделал макет (скажем my_layout.в XML), который включает в себя программно два других файла макета XML, скажем some_layout.в XML и another_layout.в XML. my_layout.в XML С помощью setContentView(R.layout.my_layout).

теперь у меня есть флажок с ID some_checkbox, который определен внутри some_layout.в XML, и я хочу поставить флажок OnCheckedChangeListener используя setOnCheckedChangeListener(), вот так:

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

но теперь NullPointerException выбрасывается, потому что cb is null. Я думаю, это потому, что макет, содержащий some_checkbox (т. е. some_layout) не загружается через setContentView(R.layout.some_layout).

  • Вопрос 1: Почему? Почему возвращает нахождения R.id.some_checkbox null? some_layout действительно is видны.
  • Вопрос 2: Как мне "загрузить"some_layout так что я могу захватить some_layout в переменную, как я пробовал в фрагменте кода наверху?

обновление

я, наконец, решил это, используя следующее, предложенное stealthjong:

одним из решений может быть инициализация checkedChangeListener, добавление прослушивателя в расширяемый listview, и когда открывается дочерний элемент расширяемого listview, проверьте, если ваш Checkbox является одним из надутых детей, и добавление checkedchangeListener если это так.

я создал метод, называемый setCheckedChangeListenerToElement(int resourceId, OnCheckedChangeListener listener), который сохраняет данный resourceId (который является идентификатором элемента, к которому нужно прикрепить прослушиватель) и данный прослушиватель. Как только inflater вызывает метод getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent), представление можно получить. Затем, на этом представлении,findViewById(int resourceId) можно назвать, где resourceId - это идентификатор флажка.

2 ответов


для этого есть два подхода.

первое добавление дочерних макетов через 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_layout1 и child_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());
    }   
}

это не дает мне false и android.widget.Button, именно так, как я заподозренный.

2. Подход Programmatical

другой подход-программный подход, и поскольку вы описали его как таковой, я подозреваю, что это то, что вы сделали (или, по крайней мере, пытались):

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>

и немного больше entrypoint приложения:

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 не завышен, пока вы фактически не откроете / не развернете раздел (см. код ниже для небольшого фрагмента кода для проверки текущего viewtree).

одним из решений может быть инициализация checkedChangeListener, добавление прослушивателя в расширяемый listview, и когда открывается дочерний элемент расширяемого 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;
}

если 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);