Reputation: 9406
I try to create new Button programatically and it to existing ViewGroup (I moved from custom to classical LinearLayout to ensure bug is not in custom ViewGroup).
A code is simple and it is working in different use case:
private void appendTile() {
View view = getLayoutInflater().inflate(R.layout.template_tile, null);
view.setId(View.generateViewId());
view.setOnClickListener(tileListener);
hiddenPicture.addView(view, view.getLayoutParams());
}
template_tile.xml:
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
style="@style/FormulaValue" />
But it fails, because view.getLayoutParams()
is null
(though there are layout_width
and layout_height
in the XML).
Caused by: java.lang.NullPointerException: Attempt to read from field 'int android.view.ViewGroup$LayoutParams.width' on a null object reference
at android.view.ViewGroup$LayoutParams.<init>(ViewGroup.java:6453)
at android.view.ViewGroup$MarginLayoutParams.<init>(ViewGroup.java:6735)
at android.widget.LinearLayout$LayoutParams.<init>(LinearLayout.java:1901)
at android.widget.LinearLayout.generateLayoutParams(LinearLayout.java:1799)
at android.widget.LinearLayout.generateLayoutParams(LinearLayout.java:62)
at android.view.ViewGroup.addViewInner(ViewGroup.java:3945)
at android.view.ViewGroup.addView(ViewGroup.java:3786)
at android.view.ViewGroup.addView(ViewGroup.java:3758)
at lelisoft.com.lelimath.activities.PuzzleActivity.appendTile(PuzzleActivity.java:39)
at lelisoft.com.lelimath.activities.PuzzleActivity.onCreate(PuzzleActivity.java:31)
I went to ViewGroups constructor and it reads width from null params. What shall I do differently in my activity? Why layout_width
from XML is not set?
Upvotes: 0
Views: 47
Reputation: 15398
LayoutParams
are specific to the container (i.e. the ViewGroup
). Since you are inflating without a root
parameter, the layout parameters are ignored, because there is simply no "proper" way to create a suitable instance of LayoutParams
without knowing the container type.
To use the layout parameters from XML, you need to supply a root ViewGroup
when inflating:
View view = getLayoutInflater().inflate(
R.layout.template_tile,
hiddenPicture,
false // don't attachToRoot
);
view.setId(View.generateViewId());
view.setOnClickListener(tileListener);
hiddenPicture.addView(view, view.getLayoutParams());
Note that the third parameter attachToRoot
is false
here. If you set it to true
, the inflated view is automatically attached to its parent container, which simplifies the typical case.
However, when attachToRoot == true
the return value from inflate()
is not the Button
instance but hiddenPicture
, i.e. the supplied root View
of the affected hierarchy.
In that case, never get direct access to the Button
object. Since you do manual setup (attach a listener, set the ID) on the inflated button, manual attach is simpler.
Upvotes: 2
Reputation: 152887
Layout params come from the parent object. Since you're inflating with a null parent, your view doesn't have layout params yet.
Replace
addView(view, view.getLayoutParams())
with
addView(view)
to not supply the layout params yourself and let the framework generate ones for you.
Upvotes: 2