This is my layout xml file:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/container1"
android:tag="1"
//... >
<TextView
android:id="#+id/txt1"
android:tag="1"
//... />
</LinearLayout>
<LinearLayout
android:id="#+id/container2"
android:tag="2"
//... >
<TextView
android:id="#+id/txt2"
android:tag="2"
//... />
</LinearLayout>
//...
It has 2 containers and one textview inside each one. Now, when I touch one button I need the container to exchange the textviews. To get this, this is my approach:
person1 = (TextView) findViewById(R.id.txt1);
person2 = (TextView) findViewById(R.id.txt2);
place1 = (LinearLayout) findViewById(R.id.place1);
place2 = (LinearLayout) findViewById(R.id.place2);
-
place1.removeView(person1);
place2.removeView(person2);
place1.addView(person2);
place2.addView(person1);
But this is what I'm getting on the LogCat:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Both the layouts contains a single TextView inside them. So instead of removing and adding views why don't you just switch the text between them? It would save your time and your performance would be better.
LinearLayout ll = (LinearLayout) findViewById(R.id.your_ll_id);
TextView tv = (LinearLayout) findViewById(R.id.your_tv_id);
ViewGroup parent = (ViewGroup) tv.getParent();
parent.removeView(tv);
tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
//...
ll.addView(tv);
You have to add textview at runtime in linearlayout rather than add textview in xml at compile time.
if you add textview at runtime it will not give you error.
linearLayout.removeAllViews();
final TextView person1 = new TextView(this);
linearLayout1.addView(person1);
final TextView person2 = new TextView(this);
linearLayout2.addView(person2);
Related
I am new to Android programming...
I want to programmatically add layouts to a ScrollView, so I use this code below
for(int i = 0; i < 10; i++){
LinearLayout myLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.my_layout, null);
ImageView imgView = (ImageView) getLayoutInflater().inflate(R.layout.img_view, null);
//set ImageView source
TextView txtView = (TextView) getLayoutInflater().inflate(R.layout.txt_view, null);
//set TextView text
myLayout.addView(imgView);
myLayout.addView(txtView);
scrllView.addView(myLayout);
}
The above code works fine. But I want to know if there is a shorter and easier way to do this, because my code will be bulky, and I will have to create a layout XML file for every view I want to add
Maybe I am thinking instead of creating multiple XML file in my layout folder, I can just have one XML file, having LinearLayout as the parent with ImageView and TextView as children, so my_layout.xml will look like this
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:id="#+id/img"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/txt"/>
</LinearLayout>
Then I can inflate my_layout.xml file in my Java code add target the ImageView and TextView using their IDs
LinearLayout myLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.my_layout, null);
ImageView imgView = //find the child of myLayout (ImageView) with ID of img
//set ImageView source
TextView txtView = //find the child of myLayout (TextView) with ID of txt
//set TextView text
I want to know if it's possible to achieve this.
Okay... I finally got what I am looking for. The code below worked perfectly
LinearLayout myLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.my_layout, null);
ImageView imgView = myLayout.findViewById(R.id.img);
//set ImageView source
TextView txtView = myLayout.findViewById(R.id.txt);
//set TextView text
I created a cycle to make a Layout with a TextView for every unit in an Array:
for(int x = 0; x<coffeeSets.length; x++) {
final View view = getLayoutInflater().inflate(R.layout.custom_list, container);
TextView tv = (TextView) view.findViewById(R.id.tv1);
TextView tv2 = (TextView) view.findViewById(R.id.tv2);
tv.setText(coffeeSets[x].name);
tv2.setText(coffeeSets[x].price + "\u20BD");
}
Here is the xml of the custom layout, if that matters:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="#color/white"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="15dp"
/>
<TextView
android:id="#+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginBottom="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="20dp"
/>
</RelativeLayout>
The problem is that it creates as many Layouts as I need, but it can only set the text for the first one:
The first layout gets the text of the last, and the last one gets empty
I understand that it because tv and tv2 are set to be 1st layout's textview, but how can I set text to other ones?
You can make inflate(R.layout.custom_list, container, false) and add the layout(container.addView(view);) manually, to appear on the screen. check below code.
The reason is if you set it to true or if you give only that layout it will be attached to the parent layout immediately, you cant add multiple items again because that view will already be added. For more detail about Inflator, you can read this article
final LinearLayout container = (LinearLayout) findViewById(R.id.container);
for(int x = 0; x<coffeeSets.length; x++) {
final View view = getLayoutInflater().inflate(R.layout.custom_list, container, false); // we can set attachToRoot as false
TextView tv = (TextView) view.findViewById(R.id.tv1);
TextView tv2 = (TextView) view.findViewById(R.id.tv2);
tv.setText(coffeeSets[x].name);
tv2.setText(coffeeSets[x].price + "\u20BD");
container.addView(view); // this you missed
}
I have a ViewFlipper under which i have a Linear Layout and Frame Layout.
I am adding imageViews and TextViews in Frame Layout dynamically from Java Class
Right now its displaying Text View at the top of my Activity and image View after it.
I want to it first display image View and then TextView
I am sharing an excerpt from my MainActivity.class
FrameLayout newsFrameLayout;
newsFrameLayout = (FrameLayout) findViewById(R.id.newsFrameLayout);
FrameLayout n1= newsFrameLayout;
ImageView imageView;
imageView = new ImageView(this);
n1.addView(imageView);
titleTextView= new TextView(this);
RelativeLayout.LayoutParams textViewParam = new RelativeLayout.LayoutParams(SlidingPaneLayout.LayoutParams.WRAP_CONTENT, SlidingPaneLayout.LayoutParams.WRAP_CONTENT);
// textViewParam.gravity= Gravity.BOTTOM;
n1.addView(titleTextView,textViewParam);
Layout File
<ViewFlipper
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="#+id/newsSliderView"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/newsLinearLayout">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:id="#+id/newsFrameLayout">
</FrameLayout>
</LinearLayout>
</ViewFlipper>
Your views are added with the default gravity which is top. You need to specify the LayoutParams with which your want the views to be added. Tο get the textview to the bottom you do this:
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.BOTTOM;
titleTextView.setLayoutParams(params);
n1.addView(titleTextView);
I have a need to create more than one TableLayout with a varied number of rows in one XML layout.
In my main layout I have an empty LinearLayout, as shown below:
<LinearLayout android:id="#+id/resultsLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
I declare this in my activity as so:
private LinearLayout linearResultsLayout;
linearResultsLayout = (LinearLayout) findViewById(R.id.resultsLayout);
I have added a table_layout.xml and a table_row.xml to my Layouts folder:
Table_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/resultsTable"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:weightSum="99"
android:background="#drawable/curvedbg"
>
</TableLayout>
Table_row.xml:
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView android:id="#+id/row_header" android:layout_weight="33" />
<TextView android:id="#+id/downstream" android:layout_weight="33"/>
<TextView android:id="#+id/upstream" android:layout_weight="33"/>
</TableRow>
My aim is to inflate the table and then inflate how ever many rows I require in to the newly inflated table whilst also passing data in the form of TextViews. The code below should give you an idea of what I'm trying to do. It doesn't work, however. NullPointerException.
private void createTable() {
String[] downResults = {"Downstream","2000","98"};
String[] upResults = {"Upstream","1000","78"};
String[] rowHeadings = {"","Bandwidth","QoS"};
TextView heading = (TextView) findViewById(R.id.row_header);
TextView downstream = (TextView) findViewById(R.id.downstream);
TextView upstream = (TextView) findViewById(R.id.upstream);
TableLayout newTable = (TableLayout) findViewById(R.id.resultsTable);
View table = inflater.inflate(R.layout.table_layout, null);
View row = inflater.inflate(R.layout.table_row, null);
linearResultsLayout.addView(table);
for(int i = 0; i < rowHeadings.length; i++){
heading.setText(rowHeadings[i].toString());
downstream.setText(downResults[i].toString());
upstream.setText(upResults[i].toString());
newTable.addView(row);
}
}
I assume it will be more complicated than how I'm trying to accomplish it.
You should probably use a ListView:
But, assuming you can't / won't, the problem you have is that you are referencing the wrong layout when you get your TextView objects. Your code should probably look more like this:
String[] downResults = {"Downstream","2000","98"};
String[] upResults = {"Upstream","1000","78"};
String[] rowHeadings = {"","Bandwidth","QoS"};
View table = inflater.inflate(R.layout.table_layout, linearResultsLayout, false));
View row = inflater.inflate(R.layout.table_row, linearResultsLayout, false));
TextView heading = (TextView) row.findViewById(R.id.row_header);
TextView downstream = (TextView) row.findViewById(R.id.downstream);
TextView upstream = (TextView) row.findViewById(R.id.upstream);
TableLayout newTable = (TableLayout) table.findViewById(R.id.resultsTable);
linearResultsLayout.addView(table);
for(int i = 0; i < rowHeadings.length; i++){
heading.setText(rowHeadings[i].toString());
downstream.setText(downResults[i].toString());
upstream.setText(upResults[i].toString());
table.addView(row);
}
Notice the row.findViewById and also the table.addView
EDIT: note the change in the layout inflater
I have Vertical ScrollView where I am going to add some Views after a buttonClick. Here is the xml of the scroll view
<ScrollView
android:background = "#drawable/border"
android:layout_weight="31"
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="0dp" >
<LinearLayout
android:id="#+id/layoutScroll"
android:padding = "10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/layoutContainer"
android:padding="5dp"
android:orientation="vertical"
android:background="#drawable/border_2"
android:layout_width="fill_parent"
android:layout_height = "wrap_content">
<RelativeLayout
android:id="#+id/relativeLayout"
android:layout_height = "wrap_content"
android:layout_width = "fill_parent">
<TextView
android:id="#+id/textWord"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/word"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/textNumber"
android:background = "#drawable/border_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text=" 1 "
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<EditText
android:id="#+id/editWord"
android:layout_marginTop="3dp"
android:layout_gravity="left"
android:inputType="text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:lines="1"
android:scrollbars="horizontal"/>
<TextView
android:id="#+id/textDefinition"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text = "#string/definition" />
<EditText
android:id="#+id/editDefinition"
android:gravity="top|left"
android:inputType="textMultiLine"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:lines="3"
android:maxLines="3"
android:scrollbars="vertical"/>
</LinearLayout>
<TextView
android:id="#+id/textEmpty"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:lines="1"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
</ScrollView>
In this function I create the same objects for adding them to the LinearLayout
private void initInterface (){
layoutScroll = (LinearLayout) findViewById (R.id.layoutScroll);
layoutContainer = new LinearLayout(getApplicationContext());
relativeLayout = new RelativeLayout(getApplicationContext());
textWord = new TextView(getApplicationContext());
textDefinition= new TextView(getApplicationContext());
textNumber = new TextView(getApplicationContext());
textEmpty = new TextView(getApplicationContext());
editWord = new EditText(getApplicationContext());
editDefinition = new EditText(getApplicationContext());
layoutContainer.setPadding(5, 5, 5, 5);
layoutContainer.setOrientation(LinearLayout.VERTICAL);
layoutContainer.setBackgroundResource(R.drawable.border_2);
LinearLayout.LayoutParams param1 =
new LayoutParams(LayoutParams.MATCH_PARENT , LayoutParams.WRAP_CONTENT );
layoutContainer.setLayoutParams(param1);
RelativeLayout.LayoutParams param2 =
new RelativeLayout.LayoutParams (RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
relativeLayout.setLayoutParams(param2);
textWord.setLayoutParams(param2);
textWord.setTextAppearance(this,android.R.style.TextAppearance_Medium);
textWord.setText("Word:");
RelativeLayout.LayoutParams param3=
new RelativeLayout.LayoutParams
(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
param3.addRule(RelativeLayout.ALIGN_PARENT_TOP);
param3.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
textNumber.setBackgroundResource(R.drawable.border_1);
textNumber.setTextAppearance(this,android.R.style.TextAppearance_Medium);
textNumber.setLayoutParams(param3);
relativeLayout.addView(textWord);
relativeLayout.addView(textNumber);
LinearLayout.LayoutParams param4 = param1;
param4.setMargins(0, 3, 0, 0);
editWord.setGravity(Gravity.LEFT);
editWord.setTextAppearance(this,android.R.style.TextAppearance_Medium);
editWord.setLines(1);
editWord.setHorizontallyScrolling(true);
editWord.setLayoutParams(param4);
textDefinition.setLayoutParams(param1);
textDefinition.setTextAppearance(this,android.R.style.TextAppearance_Medium);
textDefinition.setText("Definition:");
editDefinition.setGravity(Gravity.TOP | Gravity.LEFT);
editDefinition.setSingleLine(false);
editDefinition.setLayoutParams(param1);
editDefinition.setMaxLines(3);
editDefinition.setLines(3);
editDefinition.setVerticalScrollBarEnabled(true);
editDefinition.setImeOptions(EditorInfo.IME_FLAG_NO_ENTER_ACTION);
textEmpty.setTextAppearance(this,android.R.style.TextAppearance_Medium);
textEmpty.setLines(1);
textEmpty.setLayoutParams(param1);
layoutContainer.addView(relativeLayout);
layoutContainer.addView(editWord);
layoutContainer.addView(textDefinition);
layoutContainer.addView(editDefinition);
}
And then I add them to the Layout like this.
public void onCLick_Add(View v){
layoutScroll.addView(layoutContainer);
layoutScroll.addView(textEmpty);
}
The problem is that It only workd once . When I click the button for the second time the app crashes.
Thank you in advance.
Your log says:
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
You are trying to add same layoutContainer and textEmpty multiple times when clicking multiple times. This fails because they are already added and therefore already have a parent. (You cannot add same View to more then one parent)
Solution
I guess you want to create a new View every time you press the button and add this to your layoutScroll. You should call your init-method again for every click:
public void onCLick_Add(View v){
initInterface();
layoutScroll.addView(layoutContainer);
layoutScroll.addView(textEmpty);
}
I would also suggest to divide initInterface() into:
private View createLayoutContainer();
private View createTextEmpty();
Make sure you take initialization of scrollView outside (e.g. onCreate) and you declare views like layoutContainer localy in the createLayoutContainer() instead of globally.
Here a snippet how it would look:
private View createLayoutContainer(){
LinearLayout layoutContainer = new LinearLayout(getApplicationContext());
RelativeLayout relativeLayout = new RelativeLayout(getApplicationContext());
TextView textWord = new TextView(getApplicationContext());
...
return layoutContainer;
}
public void onCLick_Add(View v){
layoutScroll.addView(createLayoutContainer());
layoutScroll.addView(createTextEmptyView());
}
The problem occurs due to the fact that a ScrollView can only have on child View. In other words, a ScrollView can have a LinearLayout or a RelativeLayout or a TextView etc. Update your code such that new views inside are added inside LinearLayout (layoutScroll) instead of ScrollView.
As I pointed out in the comment, the bug is this : Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Checklist for these kind of bugs.
As pointed out in this post the specified child already has a parent
Double check all your addView calls.
Make sure not to add any view more then once. When a View is allready
used (e.g., you got it with findViewById, don't use addView on it.
When you want to add a view, use addView with a NEW view. You can add
several of these new views to one view, but you cannot add that one
view multiple times.
You can't re-use a view simply by changing some
stuff. You CAN re-use a variable, but you need to make a new view if
you want to re-add it using addView.