我试图实现一个简单的自定义拨号盘视图。在我尝试使用<include>
包含&#34;模板&#34;之前,一切正常。对于我的按钮而不是显式定义XML文件中的每个按钮。由于我将有12个几乎相同的按钮,我认为我只是通过这样做使我的XML更整洁更短。
问题是在我的自定义视图中的onFinishInflate()
中,当我调用findViewById(R.id.dialpad_view_btn1)
时,它返回null。我当然正在为我的dialpad_view_btn1
之一分配ID <include>
。如果我只是明确定义按钮而不是从我的&#34;模板&#34;它工作正常。是否有任何解决方法,或者我应该接受findViewById()
和<include>
不能很好地合作?
DialPadView.java
public class DialPadView extends android.support.v7.widget.GridLayout {
public DialPadView(Context context) {
super(context);
initializeViews(context);
}
public DialPadView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeViews(context);
}
public DialPadView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initializeViews(context);
}
private void initializeViews(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.dialpad_view, this);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// This call to findViewById() results in a NullPointerException
((ImageButton) findViewById(R.id.dialpad_view_btn1)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// I'm just a dummy
}
});
}
}
dialpad_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.me.myproject.DialPadView"
xmlns:grid="http://schemas.android.com/apk/res-auto"
android:id="@+id/dialpad_grid_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
grid:alignmentMode="alignMargins"
grid:columnCount="3"
grid:rowCount="4">
<include
android:id="@+id/dialpad_view_btn1"
layout="@layout/dialpad_button" />
<include
android:id="@+id/dialpad_view_btn2"
layout="@layout/dialpad_button" />
</android.support.v7.widget.GridLayout>
dialpad_button.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:grid="http://schemas.android.com/apk/res-auto">
<Button
android:layout_width="0dp"
android:layout_height="0dp"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
grid:layout_gravity="fill"
android:layout_margin="5dp"
android:scaleType="centerInside"
android:text="Test" />
</merge>
答案 0 :(得分:0)
您遇到的问题是混合<include>
和<merge>
标签造成的。
请注意,<merge>
有不同的用途,在这种情况下不应使用,因此请仅使用<incluce>
并在dialpad_button.xml文件中设置<Button>
根。然后应正确分配所有ID。
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:grid="http://schemas.android.com/apk/res-auto">
android:layout_width="0dp"
android:layout_height="0dp"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
grid:layout_gravity="fill"
android:layout_margin="5dp"
android:scaleType="centerInside"
android:text="Test" />
如果您对此问题感到好奇,可以查看LayoutInflater源文件中的parseInclude()方法。您可以找到代码处理<merge>
通胀。您可以看到,<include>
未调用将布局和id属性传递给<merge>
子项的代码,因为<merge>
应该用于不同的场景。有:
if (TAG_MERGE.equals(childName)) {
// Inflate all children.
rInflate(childParser, parent, childAttrs, false);
} else {
[...]
// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
[...]
// Attempt to override the included layout's android:id with the
// one set on the <include /> tag itself.
TypedArray a = mContext.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.View, 0, 0);
int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
// While we're at it, let's try to override android:visibility.
[...]
}
这与您丢失ID的问题并不严格相关,但正如pskink提到的那样,您在自定义<android.support.v7.widget.GridLayout>
内错误地夸大了DialPadView
,因此您最终会得到这样的层次结构:
<DialPadView>
<android.support.v7.widget.GridLayout>
<Button/>
<Button/>
</android.support.v7.widget.GridLayout>
</DialPadView>
但<DialPadView>
已经是android.support.v7.widget.GridLayout
的一个实例,所以基本上你最终在GridLayout
内有GridLayout
。除了不是最佳之外,它可能会导致布局看起来与您想象的外观和行为不同。