I have an activity where linearlayouts are added dynamically into a base linearlayout.
You'll understand from my code, but I'm trying to resuse the same "addBlock" method to add more data in the activity. If you can help me out with this, I would appreciate it! Thanks!
My code:
private void addData01() {
wii=R.drawable.img01;
d=getString(R.string.one_d); //this is later set to a seperate textview
//START OF BLOCK 1//
b1_t = getString(R.string.Title1);
b1 = new String[]{"DATA WILL GO HERE"};
b1_i = new String[]{"DATA WILL GO HERE"};
addBlock();
//START OF BLOCK 2//
b1_t = getString(R.string.Title2);
b1 = new String[]{"MORE DATA WILL GO HERE"};
b1_i= new String[]{"MORE DATA WILL GO HERE"};
addBlock();
}
private void addBlock() {
LayoutInflater inflater = LayoutInflater.from(this);
for(int i = 0 ; i < b1.length ; i++)
{
View childView = inflater.inflate(R.layout.two_row, null,false);
TextView tv = (TextView)childView.findViewById(R.id.one);
TextView tv2 = (TextView)childView.findViewById(R.id.two);
tv.setText(Html.fromHtml(b1[i]));
tv2.setText(Html.fromHtml(b1_i[i]));
b_ll.addView(b1t);
b_ll.addView(childView);
}
}
However when I do this I get the following error:
08-05 21:18:15.462: E/AndroidRuntime(4241): Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I have tried looking at this How to add same view to parent multiple times by inflating it only once but the solutions there did not seem to work
Related
I created two activites, the first one is containing the dynamic added textview and the second one will do some operation then settext to the dynamic added textview in activity one. please help to suggest a sample code for my reference. Thank you!
To add textViews can dynamically using the following method.
private void addChild(boolean right) {
LayoutInflater inflater = LayoutInflater.from(this);
int id = R.layout.unLayout_;
RelativeLayout relativeLayout = (RelativeLayout) inflater.inflate(id, null, false);
TextView textView = (TextView) relativeLayout.findViewById(R.id.textViewDate);
textView.setText(String.valueOf(System.currentTimeMillis()));
layout.addView(relativeLayout);
}
I'am stuck for about 2 hour in order to try to create a TableRow who was multiples infalted layouts in it.My code looks like this:
LayoutInflater inflater = LayoutInflater.from(this);
TableLayout tblLayout = inflater.inflate(R.layout.tblL,parent,false);
TableRow tableRow = (TableRow) tblListItems.findViewById(R.id.tableRow );
View headerCell = inflater.inflate(R.layout.header_col,tblListItems,false);
TextView tvCellName = (TextView) headerCell.findViewById(R.id.tvCellName);
for(String item: items) {
tvCellName.setText(item);
tableRow.addView(tvCellName);
}
relativeLayout2.addView(tblLayout);
The error I get :
The specified child already has a parent. You must call removeView() on the child's parent first.
What I'am doing wrong and how should I do it right ?
A view can only have one parent. You're trying to add the same view over and over again.
for(String item: items) {
tvCellName.setText(item);
tableRow.addView(tvCellName); // this will add the same view.
}
If you want to add another view you need to create the view dynamically, inside the for, and not inflate it, like:
tvCellName = new TextView(this);//this creates a new view, that doesn't have a parent.
edit
Inflate your views inside the for:
View headerCell;
TextView tvCellName;
for(String item: items) {
headerCell = inflater.inflate(R.layout.header_col,tblListItems,false);
tvCellName = (TextView) headerCell.findViewById(R.id.tvCellName);
tvCellName.setText(item);
tableRow.addView(tvCellName);
}
I have a custom view. I am trying to add multiple arrray values. But its just printing the last one. For instance check the below code. I am trying to dispay schedulePeriod.scheduleMatchups.get(i). It has two values. (get (0) and get (1). Its always getting the value of get(1) not get(0). scheduleView.add ( is returning one value not both) can anyone help me?
Thank You
private ArrayList<View> getScheduleView(final SchedulePeriod schedulePeriod) {
String teamid = FantasyFootballApplication.getFantasyTeam().teamId;
View scheduleView = playerRankingsInflate(R.layout.schedule_view);
ArrayList<View> scheduleViews = new ArrayList<View>();
for(int i=0; i<schedulePeriod.scheduleMatchups.size(); i++){
if(!(schedulePeriod.scheduleMatchups.isEmpty())) {
TextView weekNumber = (TextView) scheduleView.findViewById(R.id.week_number);
weekNumber.setText(schedulePeriod.scheduleId);
if(!(teamid.equals(schedulePeriod.scheduleMatchups.get((i)).scheduleAwayTeam.awayTeamId))) {
TextView scheduleOpp = (TextView) scheduleView.findViewById(R.id.schedule_opp);
scheduleOpp.setText(schedulePeriod.scheduleMatchups.get(i).scheduleAwayTeam.awayTeamShortName);
TextView scheduleName = (TextView) scheduleView.findViewById(R.id.schedule_teamname);
scheduleName.setText(schedulePeriod.scheduleMatchups.get(i).scheduleAwayTeam.awayTeamName);
} else if(!(teamid.equals(schedulePeriod.scheduleMatchups.get((i)).scheduleHomeTeam.homeTeamId))) {
TextView scheduleOpp = (TextView) scheduleView.findViewById(R.id.schedule_opp);
scheduleOpp.setText(schedulePeriod.scheduleMatchups.get(i).scheduleHomeTeam.homeTeamShortName);
TextView scheduleName = (TextView) scheduleView.findViewById(R.id.schedule_teamname);
scheduleName.setText(schedulePeriod.scheduleMatchups.get(i).scheduleHomeTeam.homeTeamName);
}
}
scheduleViews.add(scheduleView);
}
return scheduleViews;
}
As I can see you are creating only one view and adding it to list in for loop. And therefore you are editing only this view and you see last value in your scheduleMatchups.
You want to place your
View scheduleView = playerRankingsInflate(R.layout.schedule_view);
inside the for loop and then alter every view according and add it to your list.
Hope this helps and enjoy your work.
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
}
}
I have a LinearLayout with vertical orientation as parent, I want to add some view programmatically multiple times to this parent. Right now I am inflating the child every time getting new references to every UI element before adding to parent. This doesn't seem to be very efficient, is there any better way of doing this.
Current code I am using is below, If I inflate only once before for loop I get runtime error "he specified child already has a parent. You must call removeView() on the child's parent first."
LayoutInflater inflator = LayoutInflater.from(getBaseContext());
LinearLayout parentPanel = findViewById(R.id.parent_pannel);
ArrayList<String> myList = getData();
for(String data : myList) {
// inflate child
View item = inflator.inflate(R.layout.list_item, null);
// initialize review UI
TextView dataText = (TextView) item.findViewById(R.id.data);
// set data
dataText.setText(data);
// add child
parentPanel.addView(item);
}
Did you actually check if inflate is slow? As far as I know, inflating view is very fast (almost as fast as creating views manually).
It might be surprising for you to hear but inflate in fact does not parse the XMLs at all. XMLs for layout are parsed and pre-processed at compile time - they are stored in a binary form which makes view inflation very efficient (that's why you cannot inflate a view from an XML generated at runtime).
I'm not sure what your view is but have you creating it manually over inflating the XML:
ArrayList<String> myList = getData();
for(String data : myList) {
LinearLayout layout = new LinearLayout(this);
layout.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
TextView textView = new TextView(this);
textView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
textView.setText(data);
layout.addChild(textView);
parentPanel.addView(layout);
}
But yeah your clearly attempting something that has been done for you with Simple ListView & API
You can't, even if you try to create a new view from the old view object the object will be passed by reference not value, and hence you will got an Exception as the childAlreadyHasParent, and so, the only way is to put the view into a for loop with the number of times you want it to be inflated, and this loop must contain the creating process from beginning not only the inflating lines.
Inflating multiple times cannot be done the same way doing it in single shot. Hope this works
LayoutInflater inflator = (LayoutInflater).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout parentPanel = findViewById(R.id.parent_pannel);
ArrayList<String> myList = getData();
for(String data : myList) {
// inflate child
View item = inflator.inflate(R.layout.list_item, null);
// initialize review UI
TextView dataText = (TextView) item.findViewById(R.id.data);
// set data
dataText.setText(data);
// add child
parentPanel.addView(item);
}
This will work, at the least worked me