Reusing a TableRow - android

In order to save time when a TableLayout is populated (with repetitive data), I want to reuse TableRows. However when I try to reuse them, I get the following error:
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I am storing the TableRows in an ArrayList. I then store the ArrayList in a Hashtable. This is how I am populating the ArrayList and Hashtable:
ArrayList<TableRow> tableRowAl = AcmSinglton.rowHash.get(this.cfr);
// if ArrayList is null, populate the ArrayList with the TableRows
if (tableRowAl == null){
NodeList nodeList = (NodeList) xpath.evaluate(this.xpath, xmlSource, XPathConstants.NODESET);
for(int i=0; i<nodeList.getLength(); i++){
TableRow tr = new TableRow(this.activity);
tr.removeAllViews();
tr.setId(i);
TextView tv = new TextView(this.activity);
Element chapElement = (Element) nodeList.item(i);
tv.setText(chapElement.getAttribute(this.attribute));
tr.addView(tv);
rowsAl.add(tr);
}
// put the ArrayList<TableRow> into the hashtable for reuse
AcmSinglton.rowHash.put(this.cfr, rowsAl);
}else{
// Resuse the TableRows
this.rowsAl.addAll(tableRowAl);
}
When I try to add the TableRow to the tableLayout, I get the error:
ArrayList<TableRow> al = new ArrayList<TableRow>();
// get the Arraylist
al = xmlloaded.getRowsAl();
for (int x=0; x < al.size(); x++){
TableRow tableRow = new TableRow(this);
tableRow = al.get(x);
View child = tableRow.getChildAt(0);
final TextView tx = (TextView)child;
// I get the error here when I try to add the TableRow
tableView.addView(tableRow);
}
Thanks for the help.

On the second piece of code, try to clean the tableView before adding the Views again. Put something like this before the for block:
tableView.removeAllViews();

Related

Android Studio - removing table row programmatically

I have created a table dynamically from an array list
for (int i = 0; i < arrayList.size(); i++) {
TextView name = new TextView(this);
TextView time = new TextView(this);
TableRow row = new TableRow(this);
// Set event name and remaining time
name.setText(arrayList.get(i).name);
time.setText("...");
// Add text views to row
row.addView(time, layoutParams);
row.addView(name, layoutParams);
// Add row to table
tableLayout.addView(row, i);
}
Now if I want to edit or remove certain rows under a condition, I will have to access that row, but how?
outerloop:
for(int i = 0; i < arrayList.size(); i++ ) {
if(// row's time <= 0 ...) {
tableLayout.removeViewAt(i); // this doesn't seem to work properly
// it removes the wrong rows
}
else {
// ...
break outerloop;
}
}
For some reason tableLayout.removeViewAt(i); removes the incorrect row. Alternatively, I'd prefer to edit that row's name, but the principle applies, I just need to find a way to access the table row. Any way?
Create your table like this:
ArrayList<TableRow> rows = new ArrayList<>();
for (int i = 0; i < arrayList.size(); i++) {
TextView name = new TextView(this);
TextView time = new TextView(this);
TableRow row = new TableRow(this);
rows.add(row);
// Set event name and remaining time
name.setText(arrayList.get(i).name);
time.setText("...");
// Add text views to row
row.addView(time, layoutParams);
row.addView(name, layoutParams);
// Add row to table
tableLayout.addView(row, i);
}
When you want to remove a row now you can do that by it's index in the ArrayList:
row = rows.get(i);
table.removeView(row);
rows.remove(i);
When you want to remove multiple rows this could be a solution for you:
ArrayList<TableRow> removeRows = new ArrayList<>();
for(int i = 0; i < rows.size(); i++) {
if(....) {
removeRows.add(rows.get(i));
}
}
// now delete those rows
for(TableRow remove : removeRows) {
tableLayout.removeView(row);
rows.remove(remove);
}
I hope this works for you!

How to assign an OnClickListener for elements created through the run time?

My android app requires me to create some LinearLayouts according to data i got through the run time, so i don't know it's number and I have to put it into a for loop to create it, and as a result the name assigned to the layouts or the elements inside it will be overridden with each iterate through the for loop, and that's my code:
List<LinearLayout> inner_ver = new ArrayList<LinearLayout>();
for(int i = 0 ; i < size_from_run_time ; i++){
LinearLayout temp_inner_ver = new LinearLayout(this);
temp_inner_ver.setLayoutParams(temp_lay);
temp_inner_ver.setOrientation(LinearLayout.VERTICAL);
temp_inner_ver.setWeightSum(2);
temp_inner_ver.setPadding(7, 7, 7, 7);
inner_ver.add(temp_inner_ver);
}
for(int j = 0 ; j < inner_ver.size() ; j++){
LinearLayout icon1 = new LinearLayout(this);
inner_ver.get(j).addView(icon1);
icon1.setLayoutParams(lp_icon);
icon1.setBackgroundResource(R.drawable.ac_overlay);
icon1.setOrientation(LinearLayout.HORIZONTAL);
icon1.setTag(NORMAL);
// icon1
TextView text1 = new TextView(this);
icon1.addView(text1);
text1.setLayoutParams(text_name);
text1.setText("something");
text1.setTextSize(12);
text1.setTextColor(Color.WHITE);
ImageButton rgp1 = new ImageButton(this);
icon1.addView(rgp1);
rgp1.setLayoutParams(lp_ineer_ver);
rgp1.setImageResource(R.drawable.grp);
rgp1.setBackgroundColor(Color.TRANSPARENT);
Button rgp_value1 = new Button(this);
icon1.addView(rgp_value1);
rgp_value1.setLayoutParams(lp_ineer_ver);
rgp_value1.setText("something");
rgp_value1.setTextSize(12);
rgp_value1.setBackgroundColor(Color.TRANSPARENT);
rgp_value1.setTextColor(Color.WHITE);
ImageButton cool1 = new ImageButton(this);
icon1.addView(cool1);
cool1.setLayoutParams(lp_ineer_ver);
cool1.setImageResource(Color.TRANSPARENT);
cool1.setBackgroundColor(Color.TRANSPARENT);
TextView cool_value1 = new TextView(this);
icon1.addView(cool_value1);
cool_value1.setLayoutParams(text_cool);
cool_value1.setText("something");
cool_value1.setTextSize(12);
ver_rooms.addView(inner_ver.get(j)); // ver_rooms is a LinearLayout defined through the xml
}
So, what if i want to add an OnClickListener for the created items (e.g rgb1, rgb_value1, cool1), as I may have like 10 of inner_ver and all of them for sure contains all of these elements with the same name.
You would probably create an array or ArrayList of 10 inner_ver.Here I have assumed, innerVerList is an Array that holds List of LinearLayout.
for (LinearLayout l: list){
for(int i=0; i<l.getChildCount(); ++i){
l.getChildAt(i).addOnClickListner(/*name of onClick listener here*/ );
}
}
But I still don't get when will you need so many LinearLayouts. Though I hope it helps!
Happy coding!

Adding table rows to TableLayout from code (Remove parent error)

I am trying to add my query results to a table row inside a table layout. I keep getting java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. When i call:
((ViewGroup)table.getParent()).removeView(table);
I get an null pointer error. Any help on this would be great. Here`s the full code.
runOnUiThread(new Runnable() {
public void run() {
TableLayout table = (TableLayout)findViewById(R.id.resultstable);
int count = response.getPropertyCount();
System.out.println(count);
for(int i = 0; i < count; i++)
{
resultset.add(response.getProperty(i));
}
//TextView tv = new TextView(this);
for(int j = 0; j < resultset.size(); j++)
{
//if(resultset.get(j).toString() == "resFName")
//{
tv.setText(resultset.get(j).toString());
//((ViewGroup)row.getParent()).removeView(row);
row.addView(tv);
//((ViewGroup)table.getParent()).removeView(table);
table.addView(row);
//}
}
}
});
You are adding same TextView object to the row each time. In each iteration, create a new TextView and a TableRow.
for(int j = 0; j < resultset.size(); j++)
{
//if(resultset.get(j).toString() == "resFName")
//{
TextView tv = new TextView(context);
tv.setText(resultset.get(j).toString());
//((ViewGroup)row.getParent()).removeView(row);
TableRow row = new TableRow(context);
row.addView(tv);
//((ViewGroup)table.getParent()).removeView(table);
table.addView(row);
//}
}
You are adding the same view object to the parent. So, you are getting IllegalStateException.
If you seperate child views with "id" attribute, adding will be successful. You can give different ids to the child views via hashcode method.

Populating Table Layout using JSON String

I have a JSON String returned by my web service as follows:
{"checkrecord"[{"rollno":"abc2","percentage":40,"attended":12,"missed":34}],"Table1":[]}
The above String represents my dataset. I have converted the String to a JSON Object and I now want to put the data in the String into a TableLayout.
I want the table to be like this when displayed on android app:
rollno percentage attended missed
abc2 40 12 34
This is the code I am using as of now :
//json processing code
public void jsonprocessing(String c)
{
try
{
JSONObject jsonobject = new JSONObject(c);
JSONArray array = jsonobject.getJSONArray("checkrecord");
int max = array.length();
for (int j = 0; j < max; j++)
{
JSONObject obj = array.getJSONObject(j);
JSONArray names = obj.names();
for (int k = 0; k < names.length(); k++)
{
name = names.getString(k);
value= obj.getString(name);
createtableLayout();
}
}
}
catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//create table layout
public void createtableLayout()
{
Log.d("values",value); //I am able to see the values abc2,40,12 and 34 over here in logcat
TableLayout t= (TableLayout)findViewById(R.id.tablelayout);
TableRow r1=new TableRow(this);
r1.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
TextView t1 = new TextView(this);
t1.setText(value);
t1.setTextColor(Color.BLACK);
t1.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
r1.addView(t1);
t.addView(r1, new TableLayout.LayoutParams( LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
}
My TableLayout contains a button and a EditText as the first TableRow. After I click the button I get the JSON String. So I need to insert 2 TableRows dynamically after that as per my requirement.
My xml as of now is as follows:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tablelayout"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:background="#000044">
<TableRow>
<EditText
android:id="#+id/edittext"
android:width="200px" />
<Button
android:id="#+id/button"
android:text="Check Record"/>
</TableRow>
</TableLayout>
So my problem is how to add those 2 extra TableRows so as to populate them with the String values ?
My code isn't working fine. I am not able to get the required output.
Can anyone help me in this?
Thanks
you can use multicolumn listview for your purpose,
Parse the JSON response and get values into different strings and use this blog for your purpose
Multicolumn Listview
You, probably, can define those 2 more rows in your XML and make them initially invisible. Then upon receiving your data put your data in those rows and make them visible.
// Every UI object must have a layout parameter
int widthContent = RelativeLayout.LayoutParams.WRAP_CONTENT;
int heightContent = RelativeLayout.LayoutParams.WRAP_CONTENT;
// Create relative layout
RelativeLayout.LayoutParams rlParamsName = new RelativeLayout.LayoutParams(widthContent,heightContent);
// Create table row layout
int trWidthContent = TableRow.LayoutParams.WRAP_CONTENT;
int trHeightContent = TableRow.LayoutParams.WRAP_CONTENT;
TableRow.LayoutParams trLayout = new TableRow.LayoutParams(trWidthContent, trHeightContent);
// Create a linear layout to add new object as vertical
LinearLayout objLinearLayout = new LinearLayout(context);
objLinearLayout.setOrientation(LinearLayout.VERTICAL);
// Add number of categories to menu
for (int i = 0; i < SpecialCategories.length(); i++) {
try {
// Json for special categories
JSONObject jsonData = SpecialCategories.getJSONObject(i);
// Get name and count of category
String specialCategoryNames = jsonData.getString("label").toString();
String specialCategoryCount = jsonData.getString("coupon_count").toString();
final TableRow tr = new TableRow(this);
tr.setLayoutParams(trLayout);
tr.setId(i);
//tr.setBackgroundColor(0xFFBEBEBE);
// What is the text view for category name
TextView categoryName = new TextView(this);
categoryName.setPadding(8, 8, 8, 8);
categoryName.setTextSize(18);
categoryName.setLayoutParams(trLayout);
categoryName.setText(specialCategoryNames);
categoryName.setId(i);
categoryName.setTypeface(null, Typeface.BOLD);
categoryName.setTextColor(0xFF000000);
// What is count for category
TextView categoryCount = new TextView(this);
categoryCount.setPadding(7, 8, 8, 8);
categoryCount.setLayoutParams(trLayout);
categoryCount.setBackgroundColor(Color.WHITE);
categoryCount.setText("("+specialCategoryCount+")");
// Add disclosure image to row
ImageView objDrawLineImageView = new ImageView(this);
objDrawLineImageView.setPadding(280, 19, 6, 6);
objDrawLineImageView.setImageResource(R.drawable.disclosure);
objDrawLineImageView.setLayoutParams(trLayout);
// Add name of category
tr.addView(categoryName);
// Add count for category
tr.addView(categoryCount);
// Add disclosure back to table row
tr.addView(objDrawLineImageView);
// Add table row into linear layout
objLinearLayout.addView(tr);
//Add Row End Line to Linear layout
ImageView rowEndLine = new ImageView(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,2);
params.setMargins(0, 5, 0, 0);
rowEndLine.setLayoutParams(params);
rowEndLine.setBackgroundColor(0xFFBEBEBE);
// Add end line image to linear layout
objLinearLayout.addView(rowEndLine);
// What happen when user click on table row
tr.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(Main.this, ""+tr.getId(),Toast.LENGTH_SHORT).show();
Log.e("TAG", " clicked ID: "+tr.getId());
}
});
} catch (Exception e) {
e.printStackTrace();
}// end try
}// end for SpecialCategories.length()
//Add button number two to the activity.
RelativeLayout objRelativeLayout = (RelativeLayout)findViewById(R.id.row_special);
objRelativeLayout.addView(objLinearLayout);

Unable to select children (textview) of tableRow programmatically

I'm trying to print the value of the TextViews which are inside TableRows, using TableLayout#getChildAt(i).getChildAt(j).
When I try to log it using the above, logcat complains, saying that it's a View object and that it doesn't have the method I'm trying to use (getText()).
The only Views in the TableRows are TextViews.
// List<TextView> textViewBoxes...
private void createViews() {
...
tblLayout = new TableLayout(this);
tblRow01 = new TableRow(this);
...
for (int i = 0; i < 99; i++) {
TextView text = new TextView(this);
text.setText("Player " + i);
textViewBoxes.add(text);
}
tblRow01.addView(textViewBoxes.get(0));
...
tblLayout.addView(tblRow01);
...
// Print the contents of the first row's first TextView
Log.d(TAG, ("row1_tv1: " +
tblLayout.getChildAt(0).getChildAt(0).getText().toString));
...
}
Have you tried something like this?
TableRow row = (TableRow)tblLayout.getChildAt(0);
TextView textView = (TextView)row.getChildAt(XXX);
// blah blah textView.getText();
You can also do it in one line, but it sometimes looks ugly:
// wtf?
((TextView)((TableRow)tblLayout.getChildAt(0)).getChildAt(XXX)).getText();
Anyway... what you are doing here is casting the View to the specific type you want. You can do that without problems, since you are completely sure that each TableLayout's child is a TableRow, and you know that TableRow's children on XXX position is a TextView.

Categories

Resources