I want to replace a View in a LinearLayout programmatically. I tried the following method:
public void drawView() {
//remove previous view, if exists
if(((LinearLayout) findViewById(R.id.chartView)).getChildCount() > 0) {
((LinearLayout) findViewById(R.id.chartView)).removeAllViewsInLayout();
}
//generate new view
CustomView view = new CustomView(this,parameters);
//add new view to layout
((LinearLayout) findViewById(R.id.linLayout)).addView(view);
}
The LinearLayout that this method refers to is defined in XML:
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/linLayout">
</LinearLayout>
The view is drawn correctly the first time (when there is no view yet in the LinearLayout. But the second time drawView is called, the previous View gets removed, but no new view added. How can I replace this programmatically generated view programmatically?
you are removing from this layout ((LinearLayout) findViewById(R.id.chartView)).removeAllViewsInLayout();
but adding to this: ((LinearLayout) findViewById(R.id.linLayout)).addView(view);
replace R.id.linLayout with R.id.chartView
Related
I have a VideoView and a ListView in my RelativeLayout parent view. When the activity is Created by default the VideoView is below the ListView but I desire to change this and place the ListView below the VideoView when a button is clicked at runtime... I have tried this but am getting an error that :"Circular dependencies are not allowed in RelativeLayout"..
Here is the code I have that is throwing an exception
class Audio_Player:AppCompatActivity{
ListView audiolist;
VideoView video;
Button change;
protected override void OnCreate(Bundle savedInstanceState){
audiolist=(ListView)FindViewById<ListView>(Resource.Id.myaudiolist;
video=(VideoView)FindViewById<VideoView>(Resource.Id.myvideo);
change=(Button)FindViewById<Button>(Resource.Id.button1);
change.Click += layout_change;
}
//method to change the layout rule on button click
private void layout_change(object sender,EventArgs e) {
RelativeLayout.LayoutParams layoutParams=new RelativeLayout.LayoutParams(WindowManagerLayoutParams.MatchParent, WindowManagerLayoutParams.WrapContent);
LayoutParams.AddRule(LayoutRules.Below,video.Id);
audiolist.LayoutParameters=layoutParams;
}
}
Circular dependencies are not allowed in RelativeLayout
From the shared error, you can not modify the inner existed control of the RelativeLayout. That means you only can add View from outside of the Root RelativeLayout.
For example , create another_layout.xml as follows, and it only contains a Control. You could modify it with your needs control.
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/AnotherRootView"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:text="AnotherListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="25px"
android:id="#+id/AnotherListView" />
</LinearLayout>
Now back to Root RelativeLayout, and add android:id="#+id/RootView" in its xml.
Then we can add another_layout.xml in Root RelativeLayout as follows:
private void Change_Click(object sender, System.EventArgs e)
{
// get root view
RelativeLayout rootView = (RelativeLayout)FindViewById<RelativeLayout>(Resource.Id.RootView);
// set layout params
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(WindowManagerLayoutParams.MatchParent, WindowManagerLayoutParams.WrapContent);
layoutParams.AddRule(LayoutRules.Below, video.Id);
// get another layout
LayoutInflater inflater = (LayoutInflater)this.GetSystemService(Context.LayoutInflaterService);
LinearLayout linearLayout = (LinearLayout)inflater.Inflate(Resource.Layout.another_layout, null,true);
// get and set data for anther list view
ListView anotherListView = (ListView)linearLayout.FindViewById(Resource.Id.AnotherListView);
// we can remove the previous list view
rootView.RemoveView(audiolist);
// add another list view which inside the anther layout
rootView.AddView(linearLayout, layoutParams);
}
I want to implement custom ViewGroup in my case derived from FrameLayout but I want all child views added from xml to be added not directly into this view but in FrameLayout contained in this custom ViewGroup.
Let me show example to make it clear.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/frame_layout_child_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="#+id/frame_layout_top"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
And I want to redirect adding all child view to FrameLayout with id frame_layout_child_container.
So of course I overrode methods addView() like this
#Override
public void addView(View child) {
this.mFrameLayoutChildViewsContainer.addView(child);
}
But for sure this doesn't work because for this time mFrameLayoutChildViewsContainer is not added to the root custom view.
My idea is always keep some view on on the top in this container frame_layout_top and all child views added into custom component should go to frame_layout_child_container
Example of using custom view
<CustomFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</CustomFrameLayout>
So in this case TextView should be added to the frame_layout_child_container
Is it possible to delegate adding all views into child ViewGroup like I described.
I have other ideas like using bringToFront() method every time view is added to keep them in correct z-axis order or for example when view is added, save it to array and than after inflating custom view add all views to this child FrameLayout
Suggest what to do in this case in order not to hit performance with reinflating all layout every time new view is added, if it is possible to implement in other way.
Views inflated from a layout - like your example TextView - are not added to their parent ViewGroup with addView(View child), which is why overriding just that method didn't work for you. You want to override addView(View child, int index, ViewGroup.LayoutParams params), which all of the other addView() overloads end up calling.
In that method, check if the child being added is one of your two special FrameLayouts. If it is, let the super class handle the add. Otherwise, add the child to your container FrameLayout.
public class CustomFrameLayout extends FrameLayout {
private final FrameLayout topLayout;
private final FrameLayout containerLayout;
...
public CustomFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.custom, this, true);
topLayout = (FrameLayout) findViewById(R.id.frame_layout_top);
containerLayout = (FrameLayout) findViewById(R.id.frame_layout_child_container);
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
final int id = child.getId();
if (id == R.id.frame_layout_top || id == R.id.frame_layout_child_container) {
super.addView(child, index, params);
}
else {
containerLayout.addView(child, index, params);
}
}
}
I want to implement custom ViewGroup in my case derived from FrameLayout but I want all child views added from xml to be added not directly into this view but in FrameLayout contained in this custom ViewGroup.
Let me show example to make it clear.
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/frame_layout_child_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="#+id/frame_layout_top"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
And I want to redirect adding all child view to FrameLayout with id frame_layout_child_container.
So of course I overrode methods addView() like this
#Override
public void addView(View child) {
this.mFrameLayoutChildViewsContainer.addView(child);
}
But for sure this doesn't work because for this time mFrameLayoutChildViewsContainer is not added to the root custom view.
My idea is always keep some view on on the top in this container frame_layout_top and all child views added into custom component should go to frame_layout_child_container
Example of using custom view
<CustomFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</CustomFrameLayout>
So in this case TextView should be added to the frame_layout_child_container
Is it possible to delegate adding all views into child ViewGroup like I described.
I have other ideas like using bringToFront() method every time view is added to keep them in correct z-axis order or for example when view is added, save it to array and than after inflating custom view add all views to this child FrameLayout
Suggest what to do in this case in order not to hit performance with reinflating all layout every time new view is added, if it is possible to implement in other way.
Views inflated from a layout - like your example TextView - are not added to their parent ViewGroup with addView(View child), which is why overriding just that method didn't work for you. You want to override addView(View child, int index, ViewGroup.LayoutParams params), which all of the other addView() overloads end up calling.
In that method, check if the child being added is one of your two special FrameLayouts. If it is, let the super class handle the add. Otherwise, add the child to your container FrameLayout.
public class CustomFrameLayout extends FrameLayout {
private final FrameLayout topLayout;
private final FrameLayout containerLayout;
...
public CustomFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.custom, this, true);
topLayout = (FrameLayout) findViewById(R.id.frame_layout_top);
containerLayout = (FrameLayout) findViewById(R.id.frame_layout_child_container);
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
final int id = child.getId();
if (id == R.id.frame_layout_top || id == R.id.frame_layout_child_container) {
super.addView(child, index, params);
}
else {
containerLayout.addView(child, index, params);
}
}
}
I faced with a problem that i cannot put my dataGridView into scrollView and in case I have a lot of columns they just become so thin that it's impossible to see something there. That's why I decided to remake it and create LinearLayout with Vertical Layout for each column and each of them will have another LinearLayout with Horizontal Layout just to simulate GridView. (Hope it's a good idea)
But unfortunately I'm facing some problems during its creation. It is not being created and my application turning off. Ask you for your help
Here is my code: grid_container.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="#+id/GridScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/main_grid_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
PageFragment.java (place where LinearLayout should be fill out)
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.grid_container, container, false);
LinearLayout mainLayout = (LinearLayout) view.findViewById(R.id.main_grid_layout);
int colCount = mPage.get(0).split(",").length;
int rowCount = mPage.size();
ArrayList<ArrayList<String>> tempNormList = createNormList(mPage);
for(int currCol=0;currCol<colCount;currCol++){
LinearLayout linearLayout = new LinearLayout(view.getContext());
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
linearLayout.setLayoutParams(llParams);
for(int currRow=0; currRow<rowCount;rowCount++){
TextView textView = new TextView(view.getContext());
textView.setText(tempNormList.get(currCol).get(currRow));
if(currRow==0){
textView.setBackgroundResource(R.drawable.header_borders);
}
linearLayout.addView(textView);
}
mainLayout.addView(linearLayout);
}
return view;
}
Thank you in advance for your help
try my linked Answer, it will provide your solution, but you have do some changes like below
Don't Use Custom Adapter, use for loop with getView() method of
CustomAdapter to Set Data.
Cast your Linearlayout which id is main_grid_layout by `findViewById().
add convertView of getView() method to main_grid_layout
Skip Item Android Grid View in condition
hope it will help you
I'm trying to add a bunch of TextViews at runtime to a scrollview but I get The specified child already has a parent. You must call removeView on the child's parent first.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
testapp
#Override
public void onCreate(Bundle savedInstanceState) {
TextView[] data;
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View layout = findViewById(R.id.layout);
.......................................
data = new TextView[10];
for (int i = 0; i < 10; i++) {
data[i] = new TextView(this);
data[i].setText("data = " + i);
((ViewGroup) layout).addView(data[i]);
}
setContentView(layout);
}
You cannot use setContentView() twice in a single Activity like this. That's the problem.
Look at this answer here:
A view can only have a single parent. The view that you are adding (I am guessing re-using) is already part of another view hierarchy. If you really want to reuse it (I would suggest you probably don't) then you have to detach it from its parent in its existing view hierarchy.
I think the problem is of layout variable.
it already has a parent ScrollView view as per XML now when you are using this setContentView(layout); so this try to add layout in different parent ..