I want to inflate a XML-Layout-File in a custom ViewGroup Class, my Problem is that it produces just a empty screen. Doing the same in the Activity Class works fine. Here i
I don't know what's going on in these answers.. I think calling onLayout
manually is a bit crazy.
The LayoutInflater.inflate
function is rather straight forward. If you're using the one that accepts the 3rd boolean argument (attachToRoot) and it's true, it will add the views from your XML to your parent view (the 2nd argument). If you're using the one that accepts only 2 arguments, it will pass true to attachToRoot by default if you provide a parent that isn't null.
In any case, most of the mess you're experiencing is because the views from your XML are added to your custom view. Since your XML has a RelativeLayout
root and your custom view is also a RelativeLayout
- you're getting a relative layout inside a relative layout.
This is probably not what you want.
The answer given by Konstantin makes sense, but you're wasting a view because you're placing a RelativeLayout
inside a FrameLayout
. Since Android can't hold too many nested views, it's a good idea to optimize and not add this unnecessary FrameLayout
.
I suggest keeping your custom view as RelativeLayout
and changing your XML root to <merge>
. Then use the inflate form which adds the XML views to your parent - like View.inflate(context,int,this)
The purpose of the <merge>
tag is to skip the root node in the XML.. look it up.
Try this one:
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
inflater.inflate( R.layout.login_view_layout, null );
Did you try this?
private void initView(Context context){
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.addView(inflater.inflate(R.layout.shownumberlayout, null));
}
EDIT: I respond quickly... a ViewGroup has the responsibility to prepare the layout for their children, in the layout method try this:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
for(int i = 0 ; i < getChildCount() ; i++){
getChildAt(i).layout(l, t, r, b);
}
}
I come across the same question and answer my version in Kotlin:
You can add your customise views by xml or code. The difference is the constructor.
YourView.kt
class YourView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
init {
LayoutInflater.from(context).inflate(R.layout.your_view, this, true)
orientation = HORIZONTAL
}
}
If you want to create your layout from code then just use:
class YourView(context: Context) : LinearLayout(context)
your_view.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/searchView"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel" />
</merge>
What's the <merge>
here for?
If you use YourView
in the layout like:
<LinearLayout>
<YourView>
</YourView>
</LinearLayout>
Then the actual view hierarchy is:
with <merge>
<LinearLayout>
<TextView> </TextView>
<Button> </Button>
</LinearLayout >
without <merge>
(You need to use ViewGroup
like <LinearLayout>
)
<LinearLayout>
< LinearLayout >
<TextView> </TextView>
<Button> </Button>
</LinearLayout >
</LinearLayout>
Overriding onLayout
is necessary.when you create a object of ViewNumber(ViewGroup vg = new ViewNumber(this)
),it is like inflating xml below:
<ViewNumber
I have no child :(
</ViewNumber>
so if you don't override onLayout
,ViewNumber's onLayout
can't find any child,then it will be blank.
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
after overriding,it will use the onLayout method of ViewNumber's parent, if your codes is:
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
View.inflate(context, R.layout.shownumberlayout,this);
}
...
}
then it's like inflating xml below
<RelativeLayout
<RelativeLayout
your xml file
/>
</RelativeLayout>
there is one more RelativeLayout.To sovle this,you may write:
public class ViewNumber extends RelativeLayout {
...
private void initView(Context context){
inflater.inflate( R.layout.login_view_layout, null );
//change (..,this) to (..,null)
}
...
}
However, something unexpected will happen.android:layout_xxx=".."
of your xml file may change(this is why your text is put in the top left corner). To learn more and a better solution,you can see talkol' answer and fgeorgiew's comment under it :)
Your layout is inflated nowhere.. make your ViewNumber extend FrameLayout and inflate into it:
public class ViewNumber extends FrameLayout {
public ViewNumber(Context context) {
super(context);
initView(context);
}
public ViewNumber(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public ViewNumber(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context);
}
private void initView(Context context){
View.inflate(context, R.layout.shownumberlayout, this); //correct way to inflate..
}
}
UPD: Also you do not need to override onLayout method, that looks very incorrect.. at least call super.onLayout() on the very start:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}