Re-arrange the view order on Framelayout android - android

I've add five views on frameLayout.
how to re arrange the childIndex of framelayout.
i use below code:
fromindex = 3;
toindex = 4;
View tempFrom = frameLayout.getChildAt(fromindex);
View tempTo = frameLayout.getChildAt(toindex);
frameLayout.removeViewAt(fromindex)
frameLayout.removeViewAt(toindex)
frameLayout.addView(tempFrom, toindex)
frameLayout.addView(tempTo,fromindex)
But its throws the below error.
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
How to re arrange the childindex of framelayout ?

how to re arrange the childIndex of framelayout.
The FrameLayout doesn't have the ability to re arrange its children directly but you can do it by removing those children and re adding them in the right positions. Your code doesn't work because you remove the views in an incorrect order resulting in views still being attached to the parent:
fromindex = 3;
toindex = 4;
View tempFrom = frameLayout.getChildAt(fromindex);
View tempTo = frameLayout.getChildAt(toindex);
// first remove the view which is above in the parent's stack
// otherwise, if you remove the other child you'll call the `removeViewAt`
// method with the wrong index and the view which was supposed to be detached
// from the parent is still attached to it
frameLayout.removeViewAt(toindex);
frameLayout.removeViewAt(fromindex);
// first add the child which is lower in the hierarchy so you add the views
// in the correct order
frameLayout.addView(tempTo,fromindex)
frameLayout.addView(tempFrom, toindex)

Try this code
frameLayout.removeView(tempFrom) //to remove views
frameLayout.removeView(tempTo)

You can't swap views I think. You need to define new view group and inflate to his parent and remove old one.
View C = findViewById(R.id.C);
ViewGroup parent = (ViewGroup) C.getParent();
int index = parent.indexOfChild(C);
parent.removeView(C);
C = getLayoutInflater().inflate(optionId, parent, false);
parent.addView(C, index);

Related

How to inflate multiple instances of a layout with the same id inside an inflated layout

I have a LinearLayout with many nested LinearLayouts and TextViewss
My main activity inflates the main LinearLayout,
Then I load data from a server and based on the data received, I add multiple Layouts in a place holder (LinearLayout)
This is simple a news page where I load Images associated with the news and place it inside an initially empty LinearLayout.
Each Image has the following info: Title(TextView), Date(TextView), Image(ImageView) so what I actually do is the following:
*Please notice that this is only the essential coded in the question I elemenated all the try -> catch ... if/else ....etc
public void addImages(JSONArray images){
ViewGroup vg = (ViewGroup) findViewById(R.id.imagesPlaceHolder);
// loop on images
for(int i =0;i<images.length;i++){
View v = getLayoutInflater().inflate(R.layout.image_preview,vg);
// then
I think that here is the problem
ImageView imv = (ImageView) v.findViewById(R.id.imagePreview);
TextView dt = (TextView) v.findViewById(R.id.dateHolder);
TextView ttl = (TextView) v.findViewById(R.id.title);
// then
dt.setText("blablabla");
ttl.setText("another blablabla");
// I think the problem is here too, since it's referring to a single image
imv.setTag( images.getJSONObject(i).getString("image_path").toString() );
// then Image Loader From Server or Cache to the Image View
}
}
The code above works good for a single image
But for multiple images the Image Loader doesn't work I guess it's because all ImageViews (Inflated multiple times) have the same ID
When you provide a ViewGroup to be used as the parent, the View returned by inflate() is this parent (vg in your case) and not the newly created View. Therefore, v points toward the ViewGroup vg and not toward the newly created View and as all of your children have the same id, the same subviews (imv, dt, ttl) are returned each time.
Two solutions. The first one is to change their id right after you are finished with them, before the next iteration. Therefore, on the next creation at the beginning of the next iteration, the newly created Views will have a different IDs from the older Views because they will still use the old constant defined in R.
The other solution would be to add the parameter false to the call to inflate() so that the newly created view will not be attached to the ViewGroup and will then be returned by the inflate() function instead of the ViewGroup. The rest of your code will then works as attended with the exception that you will have to attach them to the ViewGroup at the end of the iteration.
Notice that you still need to provide a ViewGroup because it will be used to determine the value of the LayoutParams.
I had the same problem, and based on the answer from #SylvainL, here'a a working solution:
// myContext is, e.g. the Activity.
// my_item_layout has a TextView with id='text'
// content is the parent view (e.g. your LinearLayoutView)
// false means don't add direct to the root
View inflated = LayoutInflater.from(myContext).inflate(R.layout.my_item_layout, content, false);
// Now, before we attach the view, find the TextView inside the layout.
TextView tv = (TextView) inflated.findViewById(R.id.text);
tv.setText(str);
// now add to the LinearLayoutView.
content.addView(inflated);
Is there a reason why the ImageView in the layout XML needs to have an ID? Could you erase the android:id attributes from the image_preview.xml layout and then simply iterate through the children of the inflated LinearLayout? For example:
ViewGroup v = (ViewGroup)getLayoutInflater().inflate(R.layout.image_preview,vg);
ImageView imv = (ImageView) v.getChildAt(0);
TextView dt = (TextView) v.getChildAt(1);
TextView ttl = (TextView) v.getChildAt(2);
I inflate XML-Layout with dynnamic and get text of id
private val onAddView = View.OnClickListener {
val parent = viewForm.findViewById<LinearLayout>(R.id.layout_parent)
LayoutInflater.from(activity).inflate(R.layout.layout_child, parent) // layout_child has id "tv_attribute"
}
private val onSave = View.OnClickListener {
val parent = viewForm.findViewById<LinearLayout>(R.id.layout_parent)
for (i in 0 until parent.childCount) {
val getText = parent.getChildAt(i).findViewById<TextView>(R.id.tv_attribute).text
}
}

Interchange location of two views

In my activity there are two views. Both are in different parents. I have their coordinates with respect to the screen. How to interchange the location of the two views?
You will need to call the parent ViewGroup method removeView() for both views then addView() to add them back but swapper about.
So if your parent views are called mommy and daddy, one has a child called foo, the other a child called bar:
ViewGroup daddy = (ViewGroup)findViewById(R.id.daddy);
ViewGroup mommy = (ViewGroup)findViewById(R.id.mommy);
View foo = findViewById(R.id.foo);
View bar = findViewById(R.id.bar);
//detach children
daddy.removeView(foo);
mommy.removeView(bar);
//re-attach children
daddy.addView(bar);
mommy.addView(foo);
Read the reference for ViewGroup for more information about the removeView and addView methods and to see other available methods.
Try this:
int x1 = view1.getX();
int y1 = view1.getY();
view1.setX(view2.getX());
view1.setY(view2.getY());
view2.setX(x1);
view2.setY(y1);
You could also consider an animation effect to make this look nice.

How to remove a layout that was added using addContentView()?

I am adding a layout using addContentView().
How can i remove this layout on a Button click ?
Assuming contentView is the view that was added via window.addContentView()
((ViewGroup) contentView.getParent()).removeView(contentView);
try it
View youAddedView;
ViewGroup rootView = (ViewGroup) findViewById(android.R.id.content);
for (int i = 0; i < rootView.getChildCount(); i++) {
if(rootView.getChildAt(i) == yourAddedView) {
// do anything here
}
}
If you already have the reference to the view you can simply just do :
ViewGroup rootView = (ViewGroup) findViewById(android.R.id.content);
rootView.removeView(viewToRemove);
Instead of looping through the ViewGroup.
Unfortunately there's no way of removing a content view that was added with addContentView(). The best you can you do is to call setVisibility(View.GONE) on it, to hide it.
That is why the activity's onContentChanged() only gets called when the content view is set or added to an activity.
you can do two things over here you can set the visibility to gone on the click event of the button.
OR
you can set the layout parameter to layout width and height to 0dp
It will hide your layout display

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);

How to get Position of an view added dynamically on LinearLayout

I need to get an dynamically added view position in LinearLayout with vertical orientation.
For example i have 4 TextViews added dynamically on LinearLayout, then i need to change position of text colour at 3rd position will be in different color.How can i achieve it by getting position of added views.
You can do it just like that
ViewGroup parent;
int position;
for(int i = 0; i < parent.getChildCount(); ++i) {
int currentViewId = parent.getChildAt(i).getId();
if(currentViewId == wantendViewId) {
position = i;
}
}
That's (in my opinion) the simplest way
If you always know the number of TextViews in your LinearLayout, you can just use the function getChildAt( int position ). This returns a View which you can then cast to a TextView to be able to perform the desired operations.
If you do not know the number of elements you could set the id of each TextView (in order to be able to identify a particular one) and then run through them like this:
for( View view : myLinearLayout )
if( view instanceof TextView && view.getId().equals( idToSearchFor ) )
//Do what needs to be done.
I see following options:
Declare some id's in resources in form of <item type="id">first</item> and assign them to
views in adding to layout, after that use normal findViewById() mechanism
Assign some tags to views you're adding to a layout via setTag method and after that use findViewWithTag mechanism
Remeber position of your views and use them vie getChildAt method
I got simple option.
suppose you add
View v;//any view
linearlayout.addview(v);//add in layout
While u want to modify view.
simpaly remove old view.
linearlayout.removeView(v);
add new update view object
v-updated new view
linearlayout.addview(v);

Categories

Resources