LinearLayout in ExpandableListView - android

I want to inflate a childView of ExpandableChildView component.
Code:
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View v = convertView;
LinearLayout linearOpt = themesOptions.get(childPosition);
if(v == null) {
v = mInflater.inflate(R.layout.itemrow, null);
}
LinearLayout ll = (LinearLayout) v.findViewById(R.id.root);
ll.addView(linearOpt);
return v;
}
Where linearOpt is a vector that contains a lot of LinearLayout objects that I have instantiated.
private void prepareThemes(){
View v = mInflater.inflate(R.layout.widget_configure, null);
LinearLayout theme = (LinearLayout) v.findViewById(R.id.themeLayout);
LinearLayout color = (LinearLayout) v.findViewById(R.id.colorLayout);
LinearLayout trans = (LinearLayout) v.findViewById(R.id.transpLayout);
themesOptions.add(theme);
themesOptions.add(color);
themesOptions.add(trans);
}
This is R.layout.itemrow xml:
But I received this error:
07-18 10:48:49.740:
ERROR/AndroidRuntime(2738):
java.lang.IllegalStateException: The
specified child already has a parent.
You must call removeView() on the
child's parent first.
How I can resolve this issue?

I think the problem is caused by the manner you prepare the layouts in prepareThemes().
You didn't mention, but I assume your 'layout/widget_configure.xml' defines a structure like this:?
<LinearLayout android:id="#+id/root">
<LinearLayout android:id="#+id/themeLayout> <!-- ... --> </LinearLayout>
<LinearLayout android:id="#+id/colorLayout> <!-- ... --> </LinearLayout>
<LinearLayout android:id="#+id/transpLayout> <!-- ... --> </LinearLayout>
</LinearLayout>
Then you inflate this in prepareThemes() to get the 3 sub layouts. But at this moment they are already registered as children of the surrounding layout (which I called "root"). As the error implies a view instance can be added to just one parent.
You could store each LinearLayout in its own xml file and then inflate 3 times. Those stored layouts then could be add exactly once to a child.
I'm not sure what you want to do, but I would guess, it would be better - instead of preparing - to just have 3 different layouts that include the part from layout.itemrow and then just make a switch case in getChildView() and inflate the needed layout on the fly. Because even when you store a not bind layout in prepareThemes: As soon as you have more then one group you would get the same error when adding a prestored layout to the child of the snd group.
I hope this helps.

Related

How do I get a reference to a LinearLayout?

I am trying to get a reference to a LinearLayout so I can add an element.
Here is my xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context=".MainActivity">
Is it acceptable to have the line android:id="#+id/myLayout" in there?
My incorrect attempt to try and get a reference to my layout is with the following:
LayoutInflater myLayoutInflater;
LinearLayout myLayout;
if((myLayoutInflater = m_Context.getLayoutInflater()) != null) {
myLayout = (LinearLayout) myLayoutInflater.inflate(R.id.myLayout, null);
}
It underlines the R.id.myLayout in the inflate() line in red saying:
Expected resource of type Layout. Ensure resource ids passed to APIs are of the right type.
There's a misunderstanding about those methods.
LayoutInflater.inflate
This method expects the id of a layout file (and not of a layout view). So, you should call:
myLayoutInflater.inflate(R.layout.<NAME_OF_THE_XML_LAYOUT_FILE>, null);
That method will return whole view that was inflated. So, now that you have the inflated view, you can search Views inside of it. You can search view by their ID.
findViewById()
This method expects the id of the View. So, here, you should call:
View inflatedView = myLayoutInflater.inflate(R.layout.<NAME_OF_THE_XML_LAYOUT_FILE>, null);
LinearLayout linearLayout = inflatedView.findViewById(R.id.myLayout); // Assuming you added android:id="#+id/myLayout" to the LinearLayout
Note that first, we inflated the xml file and then, we started to seach for views inside of it.
HOWEVER
If your view is part of an Activity, you don't need to inflate that layout. You can instead:
public void onCreate() {
....
// This will inflate and add your layout to the actvity
setContentView(R.layout.<NAME_OF_THE_LAYOUT_FILE);
// After that line, you can call:
LinearLayout linearLayout = inflatedView.findViewById(R.id.myLayout); // Assuming you added android:id="#+id/myLayout" to the LinearLayout
// Since your view was added to the activity, you can search for R.id.myLayout
// If you search for any view before setContentView(), it will return null
// Because no view was added the screen yet
}
It is ok to find a view by id for a layout just like you do for a view:
LinearLayout layout = (LinearLayout) findViewById(R.id.myLayout);
This will do the trick if you are in an Activity context.
To add a view to it you can then do:
layout.addView(...)
You are getting that error because the LayoutInflater expects the name of the layout file not your layout id, so something like R.layout.item_layout. You also don't want to pass null for the parent view group in most cases so I would not recommend inflating it this way unless you know the parent layout.
Try something like this,
LayoutInflater myLayoutInflater = LayoutInflater.fromContext(mContext);
LinearLayout myLayout = myLayoutInflater.inflate(R.layout.layout_file, null);
View view = (LinearLayout)view.findViewById(R.id.myLayout);

How can I inflate a View subclass from XML?

I am currently populating an Adapter on startup with views inflated from XML using
private void addView(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.deal_tile, this, null);
mViews.add(view);
}
However, I've found that storing the views in a list inside the AdapterView creates problems with controls within those views, so I want to change over to use the recycling functions in Adapter#getView(int position, View recycle, ViewGroup container).
For this reason I want to use a custom view class so I can do a sanity check (if(recycle!=null && recycle instanceof CustomView)) before I repopulate it in the adapter. However, I can't find out how you inflate a custom view class from XML. I can find out how you add an inflated view to a custom view, I can find out how you insert a custom view into an XML layout, etc, and obviously I am quite happily inflating these things directly using LayoutInflater, but I can't find an equivalent for generating the custom view itself. I want to reuse the XML I already have; consequently I don't want to program in the elements (and how they look) directly.
I used this to create my own slide gallery, i think it would help.
LinearLayout internalWrapper = new LinearLayout(getContext());
internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
addView(internalWrapper);
this.mItems = items;
LinearLayout generalLayout = new LinearLayout(this.getContext());
generalLayout = (LinearLayout) View.inflate(this.getContext(), R.layout.galleryrow, null);
// inside linear layout
LinearLayout generalLinear = (LinearLayout) generalLayout.findViewById(R.id.rowgenerallin);
// set height & width to the LINEAR
generalLinear.setLayoutParams(new LayoutParams(reference_width, reference_height));
ImageView ivl = (ImageView) generalLayout.findViewById(R.id.arrow_left);
ImageView ivr = (ImageView) generalLayout.findViewById(R.id.arrow_right);
internalWrapper.addView(generalLayout);
In my case, R.layout.gallery_row contains the two images I want to manage, nested by a LinearLayous (rowgenerllin), the internal wrapper is an empty LinearLayout declared in the main layout of your activity.
Double check the LayoutParams code or you will get a big NULL :)
Cheers!

View.addView() throws IllegalStateException (ViewSwitcher)`

I have a ViewSwitcher and want to add views to it:
// initialize views
final ViewSwitcher switcher = new ViewSwitcher(this);
layMenu = (LinearLayout)findViewById(R.id.menu_main_view);
final LevelPicker levelPicker = new LevelPicker(getApplicationContext());
(//)switcher.addView(layMenu);
(//)switcher.addView(findViewById(R.layout.menu_switcher));
One is a custom view, the other one from XML. I commented one of them, but they both seem to throwIllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I tried doing several things like putting the views in a 'container' first (another layout), or tried removeView((View)getParent), like I believe the logcat tries to say..
Here's my xml file (in a nutshell):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/menu_main_view">
<TextView>
</TextView>
<LinearLayout>
<Button></Button> //couple of buttons
</LinearLayout>
</LinearLayout> //this is the parent i guess
My first guess was that all childs had to be in 1 parent, which in my case is the LinearLayout. This didn't seem to work.
Thanks
yes any View instance should have only 1 parent according to the source file
{android}/frameworks/base/core/java/android/view/View.java
in order to remove a View instance from its container, you need to do following things:
// View view = ...
ViewParent parent = view.getParent();
if (parent instanceof ViewGroup) {
ViewGroup group = (ViewGroup) parent;
group.removeView(view);
}
else {
throw new UnsupportedOperationException();
}
I guess you invoked Activity.this.setContentView(R.layout....) on the xml layout file. in this case, the parent of the LinearLayout view was another LinearLayout instance provided by a "decorate window".
it's often not a good practice to remove the only child of the "decorate window". you'd better create the children of the ViewSwitcher explicitly:
// Activity.this.setContentView(viewSwitcher);
// final Context context = Activity.this;
final android.view.LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View layMenu = inflater.inflate(R.layout...., null /* container */);
final View menuSwitcher = inflater.inflate(R.layout...., null /* container */);
viewSwitcher.addView(layMenu);
viewSwitcher.addView(menuSwitcher);

Get layout from view

I am inflating interface from XML using
View add_phone = getLayoutInflater().inflate(R.layout.phone_info, null);
Now how can i access RelativeLayout from add_phone view? is there any methos like getChildCount() ?
yes , getChildCount(), works on a ViewGroup like LinearLayout, RelativeLayout etc..
ViewGroup add_phone = (ViewGroup) getLayoutInflater().inflate(R.layout.phone_info, null);
int childCount = add_phone.getChildCount();
you must make sure the inflated layout has viewGroup as parent view, otherwise you will get class cast exception. viewGroup can be anything like LinearLayout, RelativeLayout etc..
You can find child views of a view through
View.findViewById(int id)
In your case, that translates to
RelativeLayout child = (RelativeLayout)add_phone.findViewById(R.layout.phone_info)
As long as you have unique id's for the child elements in add_phone, this should return the correct element.

How to inflate one view with a layout

I have a layout defined in XML. It contains also:
<RelativeLayout
android:id="#+id/item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
I would like to inflate this RelativeView with other XML layout file. I may use different layouts depending on a situation. How should I do it? I was trying different variations of
RelativeLayout item = (RelativeLayout) findViewById(R.id.item);
item.inflate(...)
But none of them worked fine.
I'm not sure I have followed your question- are you trying to attach a child view to the RelativeLayout? If so you want to do something along the lines of:
RelativeLayout item = (RelativeLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, null);
item.addView(child);
You inflate an XML resource. See the LayoutInflater doc .
If your layout is in a mylayout.xml, you would do something like:
View view;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.mylayout, null);
RelativeLayout item = (RelativeLayout) view.findViewById(R.id.item);
Though late answer,
but would like to add that one way to get this
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.mylayout, item );
where item is the parent layout where you want to add a child layout.
It's helpful to add to this, even though it's an old post, that if the child view that is being inflated from xml is to be added to a viewgroup layout, you need to call inflate with a clue of what type of viewgroup it is going to be added to. Like:
View child = getLayoutInflater().inflate(R.layout.child, item, false);
The inflate method is quite overloaded and describes this part of the usage in the docs. I had a problem where a single view inflated from xml wasn't aligning in the parent properly until I made this type of change.
Even simpler way is to use
View child = View.inflate(context, R.layout.child, null)
item.addChild(child) //attach to your item
Try this code :
If you just want to inflate your layout :
View view = LayoutInflater.from(context).inflate(R.layout.your_xml_layout,null); // Code for inflating xml layout
RelativeLayout item = view.findViewById(R.id.item);
If you want to inflate your layout in container(parent layout) :
LinearLayout parent = findViewById(R.id.container); //parent layout.
View view = LayoutInflater.from(context).inflate(R.layout.your_xml_layout,parent,false);
RelativeLayout item = view.findViewById(R.id.item); //initialize layout & By this you can also perform any event.
parent.addView(view); //adding your inflated layout in parent layout.
layout inflation
View view = null;
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.mylayout, null);
main.addView(view);
If you're not in an activity you can use the static from() method from the LayoutInflater class to get a LayoutInflater, or request the service from the context method getSystemService() too :
LayoutInflater i;
Context x; //Assuming here that x is a valid context, not null
i = (LayoutInflater) x.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//OR
i = LayoutInflater.from(x);
(I know it's almost 4 years ago but still worth mentioning)
AttachToRoot Set to True
Just think we specified a button in an XML layout file with its layout width and layout height set to match_parent.
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/custom_button">
</Button>
On This Buttons Click Event We Can Set Following Code to Inflate Layout on This Activity.
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.yourlayoutname, this);
Hope this solution works for you.!
If you want to add a single view multiple time then you have to use
layoutInflaterForButton = getActivity().getLayoutInflater();
for (int noOfButton = 0; noOfButton < 5; noOfButton++) {
FrameLayout btnView = (FrameLayout) layoutInflaterForButton.inflate(R.layout.poll_button, null);
btnContainer.addView(btnView);
}
If you do like
layoutInflaterForButton = getActivity().getLayoutInflater();
FrameLayout btnView = (FrameLayout) layoutInflaterForButton.inflate(R.layout.poll_button, null);
and
for (int noOfButton = 0; noOfButton < 5; noOfButton++) {
btnContainer.addView(btnView);
}
then it will throw exception of all ready added view.
If you are you trying to attach a child view to the RelativeLayout? you can do by following
RelativeLayout item = (RelativeLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, item, true);
I had the hardest time with this error, because of my unique circumstances, but finally found a solution.
My situation: I am using a separate view (XML) which holds a WebView, then opens in an AlertDialog when I click a button in my main activity view. But somehow or another the WebView belonged to the main activity view (probably because I pull the resource from here), so right before I assigned it to my AlertDialog (as a view), I had to get the parent of my WebView, put it into a ViewGroup, then remove all the views on that ViewGroup. This worked, and my error went away.
// set up Alert Dialog box
AlertDialog.Builder alert = new AlertDialog.Builder(this);
// inflate other xml where WebView is
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View v = layoutInflater.inflate(R.layout.your_webview_layout, null);
final WebView webView = (WebView) v.findViewById(R.id.your_webview_id);
// more code...
.... later on after I loaded my WebView ....
// first, remove the parent of WebView from it's old parent so can be assigned a new one.
ViewGroup vg = (ViewGroup) webView.getParent();
vg.removeAllViews();
// put WebView in Dialog box
alert.setView(webView);
alert.show();
With Kotlin, you can use:
val content = LayoutInflater.from(context).inflate(R.layout.[custom_layout_name], null)
[your_main_layout].apply {
//..
addView(content)
}
When add a layout to an Activity in Kotlin, see these steps:
Add just in Activity - One layout as a parent
Xml file of new
Layout Give the value of R.
val parent: LinearLayout =findViewById(R.id.stars)
val view =
LayoutInflater.from(applicationContext).inflate(R.layout.another, parent,false)
Where parent is not necessary, can be null But warning message will be appear
view.findViewById<ImageView>(R.id.ivTimer).setImageResource(R.drawable.t2)
Any view must be set value in this way, finally add
parent.apply { addView(view)}
I had used below snippet of code for this and it worked for me.
LinearLayout linearLayout = (LinearLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, null);
linearLayout.addView(child);

Categories

Resources