Android: Programmatically getting layout params and copying views - android

Say you have a TextView that you made in an xml file. I am wondering if it is possible to copy this view's Layout Parameters programmatically instead of having to programmatically write them all out again. Or if you could just create a new TextView and make it the same as the original one and then attach it to a new view that will be added.
I tried the latter and ran into the error that said:
08-09 22:04:55.253: E/AndroidRuntime(1848): Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
But this error would persist even after I had tried removing them from the initial view. Any ideas? Or is this just completely unfeasible and dumb.

You can always inflate a new View from the same xml. Adapter classes do this all the time, for example in ListViews the adapter will inflate all if it's rows from the same xml resource.

Of course you can get layout params for that specular TextView with;
TextView myTextView=(TextView) findViewById(<your-TextView's-id>);
ViewGroup.LayoutParams layPar=myTextView.getLayoutParams();
and you can copy another one from this and add it to new view like this;
newView.addView(newTextView);

Related

how to insert a layout in layout2?

I have created 3 layout (Principal,Hor and Ver), I need to insert layoutVer into layoutHor, and then layoutHor into layoutPrincipal
layoutVer.addView(TVTitulo,layoutParamsTitulo);
layoutVer.addView(btVer,layoutParamsBoton);
layoutHor.addView(Img,layoutParamsImagen);
layoutHor.addView(layoutVer,layoutParamsVertical);
layoutPrincipal.addView(layoutHor,layoutParamsHorizontal);
layoutPrincipal.addView(separador,layoutParamsSeparador);
this block throws me the next error
java.lang.IllegalStateException: The specified child already has a parent. You must call
removeView() on the child's parent first.
It looks like one of the views you are adding to another view (so either separador, layoutHor, layoutVer, Img, btVer, TVTitulo)
Has already been added to a view somewhere else.
So it already has a parent according to this error.
From what I can see, all of the views shown are only added to a parent view once. So that code looks fine.
Some other code must be adding one of the views to another parent.
For example if you tried to add your Img view to muliple parents you would get the same error:
layoutVer.addView(Img,layoutParamsBoton);
layoutHor.addView(Img,layoutParamsImagen);
In this example, you would be trying to give Img more than one parent.

How to resolve "The specified child already has a parent. You must call removeView() on the child's parent first."?

I have tried to add my custom layout into my main layout. I have followed the following link https://www.myandroidsolutions.com/2013/02/10/android-add-views-into-view-dynamically/#.Xa6la5MzbVo . But I am getting the error like this.
How can I resolve this?
You are adding same textview every time in your parent layout.
You have to add different view.
It can be done as-
TextView tv1 = new TextView(this);
tv1.setText("Row"+i);
parentLayout.addView(tv1)
without findviewbyid
Change parentLayout.addView(textView) to parentLayout.addView(view)
because the textView already has a parent ,i.e, the view which is inflated !.
parentLayout.addView(view)
Before add the new view you have to clear previous view
if(viewName.childCount > 0) viewName.removeAllViews()

Fragment inflating onCreateView parameters

inflater.inflate(R.layout.fragmenta , container , false);
We use this line of code for inflating. Despite read documentary , i didn't understand what is the second and third parameters function is ? What is the root in this situation and what happen if i change third to true ?
In your layout XML file some of the attributes relate to the parent container. Anything that starts with layout_*. The container, or parent in some cases, is needed to resolve those values. You can see this with things like layout_margin. If you don't give the inflater a parent you won't have any margins. But if you wrap your layout in another container like a frame layout it works. That's because it's able to resolve layout_margin using the frame layout. I'm not completely sure about the attach to parent boolean. I always get Exceptions when I set it to true.
Layout Inflater
The video should give you a good explanation of what is done and why it is done.

Why "inflate" method without specified root ignores the xml parameters?

I've read this answer : https://stackoverflow.com/a/5027921/1364174
And wonder why depending on the root parameter inflate method changes its behavior such drastically creating confusion.
According to that answer this code:
view = LayoutInflater.from(getBaseContext()).inflate(R.layout.smallred, null);
parent.addView(view);
Will create will create view specified in smallred.xml completely ignoring the properties of tags replacing them with some mysterious defaults values.
But this code will respect the properties from smallred.xml
view = LayoutInflater.from(getBaseContext()).inflate(R.layout.smallred, parent, false);
parent.addView(view);
Why is that ? Why we need to specify root/parent to which we later insert our view to, nflate" method?
Why is that necessary ? Why if we wouldn't we won't get the properties from .xml file ?
Probably because attributes are read only when you are actually inflating the view, so once you inflate it without providing the parent you will be missing information inside the inflated view. Then it doesn't matter if you add it to a parent, the data isn't there so the layout won't be as you expected it to be.
The layoutinflater doesn't know about your parent when he's inflating your view. So it doesn't even know its class. If you notice, every layout has its own LayoutParams class inside it, and you have to tell the layoutinflater which one it has to use or they will be simply discarded.

Duplicate layout IDs returning as -1 after view replacement

Short Story:
I have a layout "layout.xml", which gets replaced by another layout "success.xml" after a successful web request. Both layouts have an ImageView that provides the backgrounds to the layouts. These 2 backgrounds both need to be the same, and both are dependent on a user preference.
Longer Story: This all happens in a Fragmnet with an AsyncTask replacing the contentView with "success.xml" in onPostExecute after the web request. This happens as follows:
View view = getView();
view = null;
view = View.inflate(context, R.layout.success, null);
What I tried to do is give both ImageViews the following android:id="#+id/background_image" and then call
ImageView background = (ImageView)view.findViewById(R.id.background_image);
background.setImageResource(R.drawable.bg1);
This background-setting works for the initial view (layout.xml), but on trying to change to "success.xml", I get a NullPointException because background is null.
I've checked and the View's id is set to -1 while the original view's background_image id is set to something sensible and valid.
I've also tried setting the second view's background id like this: android:id="#id/background_image", i.e. without the '+', but still no luck.
The added complication is that it's not just 2 layouts, but about 5 that I need to do this for, so it would be really handy to recycle view id's.
Any help would be greatly appreciated.
Your code for replacing the fragment's view will not do what you want, the original view will remain the same as you change only a reference to that view and not the actual object.
To replace the view of the fragment with the new layout you could have another ViewGroup(for example a FrameLayout) in the basic layout (layout.xml) wrapping your current content(don't forget to give it an id) of layouts.xml(as I understand this is the basic layout). Then, when it's time to replace the layout you could simply do:
// remove the current content
((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)).removeAllViews();
// add the new content
View.inflate(context, R.layout.success, ((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)));
You could avoid adding an extra layout if, by any chance, all your five layouts have the same type for the root view(like a LinearLayout etc). In this case you would use the same code as above but you'll modify the other layouts file to use a merge tag. Also, you'll be looking for the id of the root in the layout.xml layout into which you'll add the content of the other files.
Then you could have the same ids, but you'll have to reinitialize any reference to the views(meaning that you'll have to search for the view again if you store a reference to the view(like a Button field in the fragment class)).

Categories

Resources