I use a for statement to create and add linearlayouts to a pre-existing vertical linearlayout. When creating them I use the for statement variable to assign an id to each one so the first layout has an id of 0 and the last has an id of 4.
for(int i = 0; i < 5; i++){
create layout
layout.setID(i);
}
I know how to change a view that's created like
Linearlayout linearLayout = new LinearLayout();
linearLayout.makeSomeChanges;
But how do I reference the layouts created in my for statement to make changes to them?
You can do it with findViewById() function. Suppose we have vertical linear layout called container. Now we can inflate there 4 items (in my case this items are linear layout with TextView inside). See the code below:
LinearLayout container = findViewById(R.id.container);
for (int i = 0; i < 5; i++) {
View child = getLayoutInflater().inflate(R.layout.item, null);
child.setId(i);
container.addView(child);
}
After adding child layouts we can access their views by ids and change any view inside them like I did with TextView:
for (int i = 0; i < 5; i++) {
View view = container.findViewById(i); // here we get child linear layout
// now we can access any view inside child linear layout and change it,
// or change some parameters of the child layout itself.
TextView textView = view.findViewById(R.id.text);
textView.setText(String.format("Changed Text %d", i));
}
Id should be ideally in resource file to avoid any coflict with existing IDs. In your case if the views are dynamic, it's not a good idea either to put those IDs in resource files.
I would recommend to use setTag() method instead of setId(). Later you can do getViewWithTag() to get the view associated with that tag.
If you are creating View (or layout) objects yourself and adding them to the screen you will have to keep track of them yourself, perhaps by a ArrayList or HashMap or any other way. note that: using setID() you may run into conflicts (two Views with same id), to avoid this you can use View.generateViewId() and keep track of all IDs you get and map them to the View.
Related
I am using a FlowLayout which is like a horizontal linear layout , but when it reaches the end of the line elements within the layout continue on the next line .
https://github.com/ApmeM/android-flowlayout
I need to programmatically delete the views on the right of a particular view within the FlowLayout , the views ( textviews ) are created programmatically :
For example (if each letter were a view )
AAAAXBBB
I want to delete the views to the right of the view X.
How I can remove programmatically the siblings to the right of the X view ?
If I keep them all in an array of views , I can do it , but it can be done without having to store the views in an array of views ?
Thanks.
Have you tried using
int children= layout.getChildCount();
for(int i=children-1; i>=0; i--) {
View child = layout.getChildAt(i);
if(child == viewX) {
break;
}
layout.removeViewAt(i);
}
This will loop over the children of the layout from the end to the beginning, removing each one until it finds the view X
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.
I am developing an app in which I am receiving json objects in json array. Each json object contains one image and two string. Now I want to show each json object's data in HorizontalScrollView i.e. if there are 10 json objects then I have to show 10 layout(with one image and two textview) in HorizontalScrollView.
What I tried is that I created a layout with one ImageView and two TextView and inflated that layout in a view object. Now at runtime I added that view object in a LinearLayout (horizontal) which is in HorizontalScrollView to the length of json array but it's giving me an error
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Can anybody tell me solution for this.
Here is my code
Linear layout ll_hori_scroll = (ViewGroup)findViewById(R.id.ll_hori_scroll);//layout in horizontal scroll view
View v = View.inflate(_activity, R.layout.list_item_recentlyadd_home, null);//custom layout
for (int i = 0; i < 2; i++) {
ll_hori_scroll.addView(v);
}
and its give error in ll_hori_scroll.addView(v);
Scrollview will allow only one child, so you have to add child layouts to child of of ScrollView.
Like this
<ScrollView
<LinearLayout
/// you can add layout's here at dynamic
</LinearLayout>
</ScrollView>
addView must add "indepent object", you just add the same "list_item_recentlyadd_home" into ll_hori_scroll twice...
The code should be below:
Linear layout ll_hori_scroll = (ViewGroup)findViewById(R.id.ll_hori_scroll);//layout in horizontal scroll view
for (int i = 0; i < 2; i++) {
//move below line from outside into for loop
View v = View.inflate(_activity, R.layout.list_item_recentlyadd_home, null);
ll_hori_scroll.addView(v);
//if you wants to use this view later, you can add the tag for your view
v.setTag(i); // v.getTag() can get their position
}
Hope it helps you... ^^
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");
}
For an Android App, I'm using a GridView and extending BaseAdapter to organize its contents. For the function getView that I override in my extended BaseAdapter class, I create a LinearLayout, which I attach an ImageView and 3 TextViews to. Now, I need to implement convertView, but because I created my views programmatically, I didn't think I can use findViewById to find these child views to change their properties (like text and bitmaps).
I had the idea of assigning a unique ID pertaining to different types of views for each one when I create them (example: give my name textview the id of 1, description textview the id of 2, etc), but I was not sure if the ids have to be unique among every view, whether they're the same kind of view or not.
Ultimately, how do I find a child view that's part of a linearlayout view which were all created programmatically?
You can get children of LinearLayout via getChildAt() but it's hard to distinguish what child exactly you get.
I think assigning IDs is better way. You can assign IDs to your views and later get views via findViewById(). IDs doesn't need to be unique for each LinearLayout.
Something like this:
// Give more sensible names to ID's
int IMAGEVIEW_ID = 0;
int TEXTVIEW1_ID = 1;
int TEXTVIEW2_ID = 2;
int TEXTVIEW3_ID = 3;
imageView.setId(IMAGEVIEW_ID);
textView1.setId(TEXTVIEW1_ID);
textView2.setId(TEXTVIEW2_ID);
textView3.setId(TEXTVIEW3_ID);
...
// somewhere later
ImageView imageView = (ImageView) convertView.findViewById(IMAGEVIEW_ID);