Как программно загрузить 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);