I have a custom XML file. I want to repeat this in a layout (say Relative) n number of times, dynamically (obviously).
I have seen many posts, but none helped. I am not looking for a ListView or Adapters or so. It's as simple as - A RelativeLayout. Inside it, adding the custom XML one above another. Any number of times.
With a static LinearLayout (Vertical orientation), adding the view dynamically results in rendering it once, not one below another. Don't know why. Although a TextView or so do repeat one below the other in a loop inside a LinearLayout (Vertical).
Then I dynamically created the layout (Relative), and inflated the custom XML. Displayed one. When I tried for another below the first it told me to remove child's parent first (Exception). If I do that and add again, its as good as removing the first rendered view and adding it again.
So how can I get multiple views in same layout?
A rough presentation of what I've attempted:
mainLayout = (RelativeLayout)findViewById(R.id.mainlay); //Mainlayout containing some views already
params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW,R.id.sideLayout); //sideLayout is an existing LinearLayout within the main layout.
View child = getLayoutInflater().inflate(R.layout.dynamiccustomlayout,null);
RelativeLayout r1 = new RelativeLayout(this);
r1.setLayoutParams(params);
r1.addView(child);
mainLayout.addView(r1);
mainLayout.setLayoutParams(params);
mainLayout.addView( child);
/* r2 = new RelativeLayout(this);
r2.setLayoutParams(params);
r2.addView(contentLayout); [Gives exception] */
This is how it worked out for me...
Before that, the issue with android is:
If you add dynamic views inside a LinearLayout (Horizontal), they will appear horizontally with new created instances, added to the view.
However, shockingly, it's not the same in case of LinearLayout (Vertical orientation). Hence the whole mess.
Solution:
The RelativeLayout layout file was binded with the variable, somewhat like this:
customLay = (RelativeLayout) mainLay.findViewById(R.id.dynamicCustomLayout);
Then, a Dynamic RelativeLayout was created within which the former variable is added/wrapped.
customLayout = new RelativeLayout(this);
customLayout.addView(customLay);
Every layout is assigned an id:
customLayout.setId(i);
And then a loop is run (2 if conditions for i=0 and i>0)
for i>0 (indicates the 2nd dynamic layout, to be added below the first), LayoutParameter is created:
params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
And then for i>0, using the ids of dynamic views, they are added one below the other:
//Following code below used id to place these views below each other to attain list type arrangement of views//
// i==0 for first view on top//
if (i == 0) {
params.addRule(RelativeLayout.BELOW, R.id.sideLayout);
customLayout.setLayoutParams(params);
}
// i>0 for views that will follow the first top//
else {
params.addRule(RelativeLayout.BELOW, i - 1);
customLayout.setLayoutParams(params);
}
Then added to main root layout, where all these views or cards need to be displayed:
includeLayout.addView(customLayout);
Ofcourse, the code is not just this. I have written the essential points that helped me achieve the target and that may help others in future.
So the main essence was ---
using a Dynamic RelativeLayout, to
bind the static RelativeLayout, and
assigning ids to the Dynamic RelativeLayout wrappers, and
on basis of ids use RelativeLayoutParameters to place the following
ids below the previous ones.
You have to instanciate every child by itself
View child = getLayoutInflater().inflate(R.layout.dynamiccustomlayout,null);
r1.addView(child);
View child2 = getLayoutInflater().inflate(R.layout.dynamiccustomlayout,null);
r1.addView(child2);
//ok, i do a analog thing in obne of my apps. here is the code:
public class FlxForm extends LinearLayout {
public FlxForm(Context context) {
super(context);
inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.flxform, this);
this.setPadding(0, 0, 0, 0);
container = (LinearLayout) this.findViewById(R.id.flxform);
this.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
//here is my funtion to calculate the items i want to add, its a little bit too complicated, but in the end it works like:
for(int i=0;i<10;i++){
View x = inflater.inflate(R.layout.dynamiccustomlayout,null);
container.addview(x);
}
}
}
XML for the Form
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/flxform"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:background="#android:color/transparent"
android:orientation="vertical" >
</LinearLayout>
Then you can instantiate a "Form" Objekt and add it into a ScrollView
For doing this You would have to nest your RelativeLayout inside a ScrollView and Manage all the Scrolling, items adding, memory management, etc manually.
So the simple solution for adding n Number of Custom Views is to use a RecyclerView, ListView, GridView, etc with a neat CustomAdapter and Your Custom View.
Here is a nice example of using RecyclerView with custom Adapter :
http://code.tutsplus.com/tutorials/getting-started-with-recyclerview-and-cardview-on-android--cms-23465
I hope this Helps.
Related
How to create a whole layout (Relative/Linear) multiple times in Android? I want the same layout to be created multiple times inside a horizontal scroll view.
You can use RecyclerView for Horizontal scrolling-
or-
Take horizontal scrollview reference in java code by findViewById.
Create one other xml for view which you want to display multiple
time.
inflate that view by getlayoutinflator. Create a loop in
view.
create a linearlayout at runtime and add those view to it by add
view
and add linearlayout to horizontal scroll view. by addview()
take a idea and modify the below code
scrollview = findViewByID(scrollview);
LinearLayout ll = new LinearLayout(this);
for(your loop){
View v= getLayoutInflator().inflate(R.layout.xml);
ll.addView(v);
}
scrollview.addView(ll);
Either you need to add inflated child views to the root view like below
RelativeLayout rootView = (RelativeLayout)findViewById(R.id.rootView);
View child = getLayoutInflater().inflate(R.layout.child, null);
rootView.addView(child);
OR you can define and include that layout multiple times inside other.
Check this link http://developer.android.com/training/improving-layouts/reusing-layouts.html
Include your reusable layout like this
<include
android:layout_width="fill_parent"
android:layout_height="wrap_content"
layout="#layout/reusabelLayout" />
I am adding multiple XML Views programmatically. I'm using a layout inflater to add them and there are no problems with that.
But I'm not able to modify the TextView in each of them.
For example, consider I am adding a LinearLayout three times in my final View. I have a TextView in that linear layout. I extract it using findViewById and if I setText("hello"); it is being reflected in the first layout, but not the second and third.
Will the inflater create new ids dynamically when adding multiple XML elements?
To answer part of your question, no: Ids are not dynamically generated by LayoutInflater.
When you say you are adding the views, where are you adding them? You mention a final View.
You don't include your code, but I assume you are calling Activity.findViewById. If you call this.findViewById from your Activity, you are traversing the entire View hierarchy and finding the first view with such an Id.
What you need to do, is iterate through all of the LinearLayouts that contain your TextViews and call findViewById on each of them.
for (LinearLayout layout : <fill in>) {
((TextView) layout.findViewById(R.id.yourid)).setText("hello");
}
As for the <fill in>. Hard to tell how to fill it in without your code. It seems like you are adding these into a parent view right? Let's assume we have a parent View parent = some view;.
You just have to get all of its children and iterate. There are a few ways you can do it depending on which subclass of View the parent is. Let's keep it simple and assuming the parent is just another LinearLayout.
In that case the for loop changes to something like:
for (int i = 0; i < parent.getChildCount(); i++) {
final LinearLayout layout = (LinearLayout) parent.getChildAt(i);
((TextView) layout.findViewById(R.id.yourid)).setText("hello");
}
I have 3 relative layouts and i need to create a single setcontetntview which is a combination of these layouts each added 3 times and sharing equal screen space and it needs to be done programatically. I started by creating a new layout adding just 2 screens,
RelativeLayout primaryLayout = new RelativeLayout(this);
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
RelativeLayout newLayout = (RelativeLayout)layoutInflater.inflate(R.layout.layout3, null, false);
RelativeLayout newLayout1 = (RelativeLayout)layoutInflater.inflate(R.layout.layout4, null, false);
primaryLayout.addView(newLayout);
primaryLayout.addView(newLayout1);
setContentView(primaryLayout);
This is displaying only the layout4. Also, if i add same layout again, its giving error stating the specified child already has a parent, you must call removeview() on the child parent first. Please help!
THe reason its displaying only layout4 is that the primaryLayout is a relative layout. Unless you specify something telling it where they go in that layout, it all goes in the upper left corner. So everything is being put on top of one another.
You can't add the same layout multiple times. You'd have to reinflate it once for every version you want, and add the results. Its like OOP- the RelativeLayout is an instance of the layout, inflating instantiates a new one.
You must use addRule to the layout param to set the views with respect to each other. As for the complaint about re-adding a view, you can try two independent instances of the view. While it will be the same layout, the parent won't know that.
EDIT:
To make occupy half screen you have to tell the parent view how much space to allot for the child view:
RelativeLayout.LayoutParams forChild = new RelativeLayout.LayoutParams(30,40);
childView.setLayoutParams(forChild);
Right, this is a strange problem I have been toying with for a while now, hopefully maybe I am missing something you guys can draw my attention to!
LinearLayouts seem to be disappearing once I add any spacing using views and defining the weight (a method which works elsewhere in the project).
I have a custom Dialog (extends Dialog). In the onCreate() I use the method setContentView(generateDialog()) which returns a vertical LinearLayout.
The LinearLayout has three elements, one row of four custom category buttons (LinearLayouts), one row of sorting buttons (also LinearLayouts) and one ListView which populates the rest of the dialog and refreshes based on which button is pressed.
All is functional and working fine. Except when I attempt to space the buttons out evenly using my spacer method:
Dialog.java:
LinearLayout catBtns = new LinearLayout(context);
catBtns.setOrientation(LinearLayout.HORIZONTAL);
catBtns.setBackgroundResource(R.drawable.btn_cat_gradient_bg);
catBtns.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
catBtns.addView(space(1));
cat1Btn = new CatButton(context,this,act,"CAT1");
catBtns.addView(cat1Btn);
catBtns.addView(space(1));
cat2Btn = new CatButton(context,this,act,"CAT2");
catBtns.addView(cat2Btn);
catBtns.addView(space(1));
cat3Btn= new CatButton(context,this,act,"CAT3");
catBtns.addView(cat3Btn);
catBtns.addView(space(1));
cat4Btn = new CatButton(context,this,act,"CAT4");
catBtns.addView(cat4Btn);
catBtns.addView(space(1));
The space() method:
private View space(int space) {
View view = new View(context);
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(0,0);
p.weight = space;
view.setLayoutParams(p);
return view;
}
What confuses me is that I have been using this method throughout the project and can't find as to why the category LinearLayout DISAPPEARS COMPLETELY when I add the spacers in between each button.
I use the same technique for the sorting buttons and it works perfectly! I use the same technique in another part of the project using slightly different versions of the same buttons (they are different class files though, because the onClickListener and some other stuff is slightly different)
Anyone have any clue?
I tried to build this in XML and it works fine. A possible difference is, that you do not set any LayoutParams for your buttons. Try something like that for every button:
cat1Btn = new CatButton(context,this,act,"CAT1");
catBtns.addView(cat1Btn, new LinearLayout.LayoutParams(0,0));
Is there a way to create an array containing actual instances of views. For example, if I have one LinearLayout called Container that has within it 3 other LinearLayouts with the same Tag attribute and I wanted to get a list containing all 3 LinearLayouts so I can loop through and handle each.
Tried:
LinearLayout[] layouts = (LinearLayout[]) Container.FindViewWithTag(tag);
and
List<LinearLayout> layouts = (List<LinearLayout>) Container.FindViewWithTag(tag);
and
foreach(LinearLayout layouts in Container.FindViewWithTag(tag))
None of these have been acceptable to Android so far. Another acceptable way to handle my situation would be to just be able to assign each LinearLayout a Parent. But I haven't found a way to programatically set a view's parent, only how to get a view's parent.
What I have understood from your question that you want the child of Linear Layout. Yes, you can get the child of linear layout by container.getChild(index)
for(int i=0;i<container.getChildCount();i++){
View child=container.getChildAt(i);
//your processing....
}