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 ..
Related
I'm following the accepted answer to this question:
ArrayList<EditText> myEditTextList = new ArrayList<EditText>();
for( int i = 0; i < myLayout.getChildCount(); i++ )
if( myLayout.getChildAt( i ) instanceof EditText )
myEditTextList.add( (EditText) myLayout.getChildAt( i ) );
How do you get myLayout, what does it actually represent? In my app I define linear_layout in activitymain.xml but can't seem to get it in MainActivity.java (I tried using R but it didn't work). I'm new to Android development and could really use some high level guidance.
Let Linear Layout be the root of your xml:
<LinearLayout android:id="#+id/my_layout" >
//your views goes here
</LinearLayout>
Then in your Activity you'll have to initialize the view once your layout gets inflated like this
LinearLayout myLayout = (LinearLayout) findViewById(R.id.my_layout);
Hope this helps.
You need to use myLayout as your root layout in your layout.xml file
the myLayout maybe a FrameLayout, LinearLayout, RelativeLayout or ConstraintLayout layout
SAMPLE CODE
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/myLayout"
android:orientation="vertical">
<!-- add your view here-->
</LinearLayout>
Now do findViewById in side your actvity
public class MyActivity extends AppCompatActivity {
LinearLayout myLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
myLayout = findViewById(R.id.myLayout);
}
}
You can try below code to get a reference of your LinearLayout in Java code.
LinearLayout myLayout=(LinearLayout) findViewById(R.id.your_linear_layout_id)
assuming your actiivtymain.xml looks like this
<?xml version="1.0" encoding="utf-8"?>
<SomeLayout
android:id="#+id/some_id"
...>
<EditText
...
/>
<EditText
...
/>
.
.
.
</SomeLayout>
mLayout you are referring is the parent of all your edit texts. It may not be the root of your layout but if you want to get a Java instance of it, you need to give it an id. and get the instance by using the code given by #Nilesh Rathod. One more thing to remember is to call the method findViewById(R.id.my_layout); only after setContentView(R.layout.activitymain);.
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
My XML file is the following:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/border">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rants_list_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
I then have a res/layout/sonich.xml file:
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:id="#+id/sonich"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="32sp"
xmlns:android="http://schemas.android.com/apk/res/android"/>
My goal is to make the above TextView a reusable view, that is, reference it in the application multiple times to create text views of the properties specified in the above text view.
Hence, in the main activity, I do the following:
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.rants_list_linear_layout);
for (int i = 0; i< 100; i++) {
TextView txt = (TextView) findViewById(R.id.sonich);
linearLayout.addView(txt);
}
This, however, produces the following error:
java.lang.IllegalArgumentException: Cannot add a null child view to a
ViewGroup
This suggests that the findViewById() method returns a null reference. I do not understand why, since the text view is well defined in the xml file and the findViewById() method works well for the linear layout a few lines before that.
If I change the code to:
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.rants_list_linear_layout);
for (int i = 0; i< 100; i++) {
TextView txt = new TextView(this);
txt.setText("TextView");
txt.setTextSize(32);
linearLayout.addView(txt);
}
everything works fine. However, this is not what I want. I would like to outsource as much code to the xml files as possible. After all, the xml files exist to provide an organised way of specifying layouts, views etc. and their properties, whereas Java code is the one dealing with the app's functionality.
Could you please explain what this error stems from and how to create text views (or any views) programmatically, while referencing xml files to infer the views' properties?
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.rants_list_linear_layout);
LayoutInflater inflater = LayoutInflater.from(linearLayout.getContext());
for (int i = 0; i< 100; i++) {
View sonich = inflater.inflate(R.layout.sonich, linearLayout, false);
TextView txt = (TextView) sonich.findViewById(R.id.sonich);
// Now you don't need to do these since the XML takes care of it
// txt.setText("TextView");
// txt.setTextSize(32);
linearLayout.addView(txt);
}
I am working on an Android project and I have an issue with the layout.
What I have is a JSONArray that I loop round inflating a new TableRow and within the loop round another array within the JSON array to populate it with fields. The fields are populated by inflating an XML file and adding this view to the table row. However, at the moment nothing shows up in the row.
Below is my TableRow XML file:
<?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="wrap_content"
android:background="#color/white"/>
Below is my TextView XML:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="#color/black"
android:padding="5dp"/>
Below is how I am populating the TableRow and the TextView:
for (int i = 0; i < result.length(); i++) {
final TableRow tr = (TableRow) getLayoutInflater(getArguments()).inflate(R.layout.result_table_row_light_theme, resultTable, false);
if (i == 0) {
tr.setBackgroundColor(getResources().getColor(R.color.appPrimaryColour));
} else if (i % 2 == 0) {
if (settings.getInt(Defines.SharedPreferenceSettings.APPLICATION_THEME,
com.BoardiesITSolutions.Library.R.style.LibAppTheme) == com.BoardiesITSolutions.Library.R.style.LibAppTheme) {
tr.setBackgroundColor(getResources().getColor(R.color.resultRowLightThemeAlternateRow));
}
}
JSONArray array = result.getJSONArray(i);
for (int j = 0; j < array.length(); j++) {
final TextView textView;
textView = (TextView) getLayoutInflater(getArguments()).inflate(R.layout.result_textview, tr, false);
textView.setText(array.getString(j));
if (i == 0) {
textView.setTypeface(null, Typeface.BOLD);
textView.setGravity(Gravity.CENTER_HORIZONTAL);
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
tr.addView(textView);
}
});
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
resultTable.addView(tr);
}
});
}
If I change my TextView XML file so that the layout_width is wrap_parent instead of 0dp then everything is shown on the screen.
However, when the textview is 0dp and the layout_weight is 1 then nothing is displayed, however I would have expected each text view to be evenly distributed across the width of the screen to fill the space.
What I should probably mention, don't know if it makes a difference, is the TableView is within a HorizontalScrollView. The row should fit in the width of the screen, if the data is smaller than the screen, but if the row won't fit, then the view will be horizontally scrollable.
UPDATE 1
Below is the XML that hosts the TableLayout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="horizontal">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableLayout android:id="#+id/resultTable"
android:stretchColumns="*"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</TableLayout>
</HorizontalScrollView>
</LinearLayout>
</ScrollView>
</RelativeLayout>
What I should probably mention, don't know if it makes a difference, is the TableView is within a HorizontalScrollView.
It is a logical error to tell a child view inside a scrolling container to match_parent or fill the available space in any way. A scrolling container, like ScrollView or HorizontalScrollView measures its one-and-only child view as UNSPECIFIED so that the child can grow beyond the parent bound in that one direction (and, thus, be scrollable).
The child of a scrolling container is not given what the "available space" would be for it to fill, and operations like layout weight have no effect if the parent's dimension is not well-defined.
The row should fit in the width of the screen, if the data is smaller than the screen, but if the row won't fit, then the view will be horizontally scrollable.
The functionality you are looking for is fillViewport (docs link), which tells the scrolling container to force the child to match it's size if the measured width (in the horizontal case) is less than the parent. Use this in place of applying a weight.
Try this :
public void createTextView(Context context, LinearLayout parent) {
final TextView v = new TextView(context);
parent.addView(v); // Mandatory!
v.post(new Runnable() { // In UI Thread. View Must be added to parent before getting layout params!
#Override
public void run() {
// Get params:
LinearLayout.LayoutParams lParams = (LinearLayout.LayoutParams) v.getLayoutParams();
// Set only target params:
lParams.width = 0;
lParams.weight = 1;
v.setLayoutParams(lParams);
}
});
}
Can you try to do your layout in XML (just to debug it, with dummy data)? Does it work as expected?
The docs mention that:
children of a TableRow do not need to specify the layout_width and layout_height attributes in the XML file. TableRow always enforces those values to be respectively MATCH_PARENT and WRAP_CONTENT.
Not sure if that means that it'll also mess stuff up if you try to set these values. As you've found, it's clearly not just ignoring them if they are set.
The other part says that the parent of the TableRow should be a TableLayout - is that the type of resultTable (you mentioned TableView) - otherwise it will behave as a LinearLayout with horizontal orientation.
I just started android and I tried below questions to get this answer before posting it here:
Android - Adding layout at runtime to main layout
Add button to a layout programmatically
Dynamically adding a child to LinearLayout with getting each child's position
And I am still not able to add a button to linear layout :(
Below is the code for activity, please let me know where I am wrong:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout layout = (LinearLayout) View.inflate(this, R.layout.activity_main, null);
Button btn = new Button(this);
btn.setId(123);
btn.setText("Welcome to WI FI World");
layout.addView(btn);
}
And xml looks like below:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</LinearLayout>
Try assigning an id to your layout then add the button to the layout.
Im pretty sure those 2 layouts are not the same, so you are infact adding a button to a layout that is never displayed.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout layout = (LinearLayout) findViewById(R.id.lnr_main);
Button btn = new Button(this);
btn.setId(123);
btn.setText("Welcome to WI FI World");
layout.addView(btn);
}
With Layout assigned an id
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/lnr_main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</LinearLayout>
Take the Id for LinearLayout in XML and in jave code use that id of LinearLayout from XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/linear" >
</LinearLayout>
In onCreate():
LinearLayout linear=(LinearLayout)findViewById(R.id.linear);
//Select widgets
linear.addView()
Give an id to your linearLayout.
Then in your code
LinearLayout layout = (LinearLayout)findViewById(R.id.given_id);
Keep the rest the same, should work.