I want to get data from database in my android table view.
Should I use loop? Is static good for this?
This may be useful for you..
try{
JSONArray jArray = new JSONArray(result);
TableLayout tv=(TableLayout) findViewById(R.id.table);
tv.removeAllViewsInLayout();
int flag=1;
// when i=-1, loop will display heading of each column
// then usually data will be display from i=0 to jArray.length()
for(int i=-1;i<jArray.length();i++){
TableRow tr=new TableRow(Yourclassname.this);
tr.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
// this will be executed once
if(flag==1){
TextView b3=new TextView(Yourclassname.this);
b3.setText("column heading 1");
b3.setTextColor(Color.BLUE);
b3.setTextSize(15);
tr.addView(b3);
TextView b4=new TextView(Yourclassname.this);
b4.setPadding(10, 0, 0, 0);
b4.setTextSize(15);
b4.setText("column heading 2");
b4.setTextColor(Color.BLUE);
tr.addView(b4);
TextView b5=new TextView(Yourclassname.this);
b5.setPadding(10, 0, 0, 0);
b5.setText("column heading 3");
b5.setTextColor(Color.BLUE);
b5.setTextSize(15);
tr.addView(b5);
tv.addView(tr);
final View vline = new View(Yourclassname.this);
vline.setLayoutParams(new
TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, 2));
vline.setBackgroundColor(Color.BLUE);
tv.addView(vline); // add line below heading
flag=0;
} else {
JSONObject json_data = jArray.getJSONObject(i);
TextView b=new TextView(Yourclassname.this);
String str=String.valueOf(json_data.getInt("column1"));
b.setText(str);
b.setTextColor(Color.RED);
b.setTextSize(15);
tr.addView(b);
TextView b1=new TextView(Yourclassname.this);
b1.setPadding(10, 0, 0, 0);
b1.setTextSize(15);
String str1=json_data.getString("column2");
b1.setText(str1);
b1.setTextColor(Color.WHITE);
tr.addView(b1);
TextView b2=new TextView(Yourclassname.this);
b2.setPadding(10, 0, 0, 0);
String str2=String.valueOf(json_data.getInt("column3"));
b2.setText(str2);
b2.setTextColor(Color.RED);
b2.setTextSize(15);
tr.addView(b2);
tv.addView(tr);
final View vline1 = new View(Yourclassname.this);
vline1.setLayoutParams(new
TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, 1));
vline1.setBackgroundColor(Color.WHITE);
tv.addView(vline1); // add line below each row
}
}
}catch(JSONException e){
Log.e("log_tag", "Error parsing data " + e.toString());
Toast.makeText(getApplicationContext(), "JsonArray fail", Toast.LENGTH_SHORT).show();
}
I see this post is pretty old, but if someone else is facing also the issue to display custom data in a Table in Android, I would like to offer my TableView as possible solution to do so.
So you do not care about how to fill the data to your table, you can simply create a custom adapter for the data you want to show (like we already know in Android from views like the ListView).
our code will look like this:
List<Flight> myData = new ArrayList<>();
myData.add(new Flight(...));
myData.add(new Flight(...));
myData.add(new Flight(...));
TableView<Flight> table = findViewById(R.id.table);
table.setHeaderAdapter(new SimpleHeaderAdapter("Time", "Airline", "Flight", "Destination"));
table.setDataAdapter(new FlightDataAdapter(myData));
The result could look like this:
rs1 = stmt.executeQuery("SELECT * from message");
StringBuilder sb = new StringBuilder();
while (rs1.next())
{
String script = rs1.getString(1);
String call = rs1.getString(2);
String price = rs1.getString(3);
String stoploss = rs1.getString(4);
String target = rs1.getString(5);
String ltp = rs1.getString(6);
String exit = rs1.getString(7);
sb.append(script).append(";").append(call).append(";").append(price).append(";").append(stoploss).append(";").append(target).append(";").append(ltp).append(";").append(exit).append("_");
}
out.print(sb.toString());
out.flush();
for this you have XML
for this you have a XML like
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="horizontal" android:layout_marginTop="20dip">
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/tab"
>
<TableRow>
</TableRow>
</TableLayout>
</LinearLayout>
to show the data in the android you write.
String st = new String(str);
Log.e("Main",st);
String[] rows = st.split("_");
TableLayout tableLayout = (TableLayout)findViewById(R.id.tab);
tableLayout.removeAllViews();
for(int i=0;i<rows.length;i++){
String row = rows[i];
TableRow tableRow = new TableRow(getApplicationContext());
final String[] cols = row.split(";");
Handler handler = null;
for (int j = 0; j < cols.length; j++) {
final String col = cols[j];
final TextView columsView = new TextView(getApplicationContext());
columsView.setText(String.format("%7s", col));
tableRow.addView(columsView);
That depends. If you're sure that you'll have only a few rows then you can inflate add them in loop to the TableLayout. But note that you create view for every row.
With lot of data create ListView and adapter for example based on CursorAdapter:
public class MyCursorAdapter extends CursorAdapter {
private static final String TAG = "MyCursorAdapter";
private final int NAME_COLUMN;
private final int ADDRESS_COLUMN;
private final int STATE_COLUMN;
public MyCursorAdapter(Context context, Cursor c) {
super(context, c);
NAME_COLUMN = c.getColumnIndexOrThrow("name");
ADDRESS_COLUMN = c.getColumnIndexOrThrow("address");
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.custom_row, null);
MyRowViewHolder rowData = new MyRowViewHolder();
rowData.name = (TextView) view.findViewById(R.id.name);
rowData.address = (TextView) view.findViewById(R.id.address);
rowData.name.setText(cursor.getString(NAME_COLUMN));
rowData.address.setText(cursor.getString(ADDRESS_COLUMN));
view.setTag(rowData);
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
MyRowViewHolder rowData = (MyRowViewHolder) view.getTag();
rowData.name.setText(cursor.getString(NAME_COLUMN));
rowData.address.setText(cursor.getString(ADDRESS_COLUMN));
}
public static class MyRowViewHolder {
TextView name;
TextView address;
}
}
This approach doesn't create view for every row. I think that's better but needs more effort. To get table layout style use LinearLayout for rows with layout_weight for columns
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/name"
android:layout_weight="0.25"
android:layout_width="0"
android:layout_height="wrap_content">
</TextView>
<TextView
android:id="#+id/address"
android:layout_weight="0.75"
android:layout_width="0"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
To the ListView add header and footer if you want.
Static can be used when you have a defined never changing number of rows/cols in your table you want to fill. Otherwise I suggest to use a loop and add a row to the table view for each step in your loop.
We could imagine a custom component for android : the TableView.
Its code would be something like :
public class TableView extends TableLayout {
public TableView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TableView(Context context) {
super(context);
}
public void setAdapter(TableAdapter<?> adapter) {
removeAllViews();
for (int row = 0; row < adapter.getRowCount(); row++) {
TableRow tableRow = new TableRow(getContext());
TableLayout.LayoutParams params = new TableLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
tableRow.setLayoutParams(params);
addView(tableRow);
for (int column = 0; column < adapter.getColumnCount(); column++) {
View cell = adapter.getView(row, column);
tableRow.addView(cell);
TableRow.LayoutParams cellParams = (android.widget.TableRow.LayoutParams) cell.getLayoutParams();
cellParams.weight = adapter.getColumnWeight(column);
cellParams.width = 0;
}
}
}
}
And it would use an adapter like this :
public interface TableAdapter<T> {
int getRowCount();
int getColumnWeight(int column);
int getColumnCount();
T getItem(int row, int column);
View getView(int row, int column);
}
Related
I want create N edit text with pressing a button only once. for example I enter quantity of edit texts=20[enter image description here][1], when I press button all of 20 edit texts created in several rows and columns.
Any solutions??
sample picture for better solution [1]: https://i.stack.imgur.com/wevZN.png
my code is in below
String Type,number,tedad;
TextView pazireshnum;
EditText tedadbattri;
String id=ID;
private LinearLayout mLayout;
private EditText mEditText;
private ImageButton mButton;
int k = -1;
int flag,i;
int hint=1;
ArrayList<String> applnserverinstnos = new ArrayList<String>();
public static EditText textView[] = new EditText[100];
#SuppressLint("WrongViewCast")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check_list);
mLayout = (LinearLayout) findViewById(R.id.ln1);
// mEditText = (EditText) findViewById(R.id.editText);
mButton = (ImageButton) findViewById(R.id.imgbtn);
tedadbattri=(EditText) findViewById(R.id.ed7);
tedadbattri.setText("0");
pazireshnum=(TextView)findViewById(R.id.tv4);
tedad= tedadbattri.getText().toString();
int Tedad = Integer.parseInt(tedad);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
k++;
flag = k;
final LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lparams.setMargins(5, 10, 5, 10);
textView[flag] = new EditText(CheckList.this);
textView[flag].setLayoutParams(lparams);
textView[flag].setId(flag);
textView[flag].setPadding(5, 5, 5, 5);
} catch (Exception e) {
e.printStackTrace();
}
mLayout.addView(textView[flag]);
textView[flag].setHint("باتری"+hint);
hint++;
textView[flag].setId(hint);
textView[flag].setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
textView[flag].setBackgroundResource(R.drawable.border4);
}
});
You may check this procedure , suppose 20 can be divided 4 columns with 5 rows . So run for loop on columns and rows to add editText view to TableRow with TableLayout .
Example main_activity.xml where used TableLayout to add EditText .
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<ImageButton
android:id="#+id/imgbtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="137dp"
tools:layout_editor_absoluteY="283dp" />
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/table">
</TableLayout>
</LinearLayout>
Now try the code -
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int total = 20; // quantity of edit texts 20
final int columns = 4;
final int rows = total / columns; // in this case rows would be 5
TableLayout myTable = findViewById(R.id.table);
//Params for TableRow and TableLayout
final TableLayout.LayoutParams tableParams = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT);
final TableRow.LayoutParams rowParams = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1);
//apply to clear
myTable.removeAllViews();
for (int i = 0; i < rows; i++) {
TableRow tableRows = new TableRow(getApplicationContext());
for (int j = 0; j < columns; j++) {
EditText editText = new EditText(getApplicationContext());
editText.setText("voltage" + total--);
tableRows.addView(editText, rowParams);
}
myTable.addView(tableRows, tableParams);
}
}
});
Output-
You can use a for loop and create EditTexts in that loop and add them to a FlowLayout container; Maybe this implementation or ConstraintLayout's Flow
I want to add radiobuttons for every cell in given below table and get their position based on row and column, how to achieve it? Kindly share your views. Thanks in advance. I have commented the code where i was adding text to each cells, may be at the same place we can add radiobuttons
Below is working code :
public class MainActivity extends Activity {
RelativeLayout rl;
RadioGroup rg;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String[] row = { "AA", "BB", "CC", "DD", "EE", "FF", "GG" };
String[] column = { "Col 1", "Col 2", "Col 3", "Col 4", "Col 5", "Col 6" };
int rl = row.length;
int cl = column.length;
Log.d("--", "R-Lenght--" + rl + " " + "C-Lenght--" + cl);
ScrollView sv = new ScrollView(this);
TableLayout tableLayout = createTableLayout(row, column, rl, cl);
HorizontalScrollView hsv = new HorizontalScrollView(this);
hsv.addView(tableLayout);
sv.addView(hsv);
setContentView(sv);
}
public void makeCellEmpty(TableLayout tableLayout, int rowIndex, int columnIndex) {
// get row from table with rowIndex
TableRow tableRow = (TableRow) tableLayout.getChildAt(rowIndex);
// get cell from row with columnIndex
TextView textView = (TextView) tableRow.getChildAt(columnIndex);
// make it black
textView.setBackgroundColor(Color.BLACK);
}
public void setHeaderTitle(TableLayout tableLayout, int rowIndex,
int columnIndex) {
// get row from table with rowIndex
TableRow tableRow = (TableRow) tableLayout.getChildAt(rowIndex);
// get cell from row with columnIndex
TextView textView = (TextView) tableRow.getChildAt(columnIndex);
textView.setText("Hello");
}
private TableLayout createTableLayout(String[] rv, String[] cv,
int rowCount, int columnCount) {
// 1) Create a tableLayout and its params
TableLayout.LayoutParams tableLayoutParams = new TableLayout.LayoutParams();
TableLayout tableLayout = new TableLayout(this);
tableLayout.setBackgroundColor(Color.BLACK);
// 2) create tableRow params
TableRow.LayoutParams tableRowParams = new TableRow.LayoutParams();
tableRowParams.setMargins(1, 1, 1, 1);
tableRowParams.weight = 1;
for (int i = 0; i < rowCount; i++) {
// 3) create tableRow
TableRow tableRow = new TableRow(this);
tableRow.setBackgroundColor(Color.BLACK);
final RadioButton[] rb = new RadioButton[10];
rl=(RelativeLayout) findViewById(R.id.rl);
rg=new RadioGroup(this);
for (int j = 0; j < columnCount; j++) {
// 4) create textView
TextView textView = new TextView(this);
// textView.setText(String.valueOf(j));
textView.setBackgroundColor(Color.WHITE);
textView.setGravity(Gravity.CENTER);
String s1 = Integer.toString(i);
String s2 = Integer.toString(j);
String s3 = s1 + s2;
int id = Integer.parseInt(s3);
Log.d("TAG", "-___>" + id);
if (i == 0 && j == 0) {
textView.setText("0==0");
} else if (i == 0) {
Log.d("TAAG", "set Column Headers");
textView.setText(cv[j - 1]);
} else if (j == 0) {
Log.d("TAAG", "Set Row Headers");
textView.setText(rv[i - 1]);
} else {
/*textView.setText("" + id);
// check id=23
if (id == 23) {
textView.setText("ID=23");
}*/
//Add Radiobuttons here
}
// 5) add textView to tableRow
tableRow.addView(textView, tableRowParams);
}
// 6) add tableRow to tableLayout
tableLayout.addView(tableRow, tableLayoutParams);
}
return tableLayout;
}
}
please use listview instead of table layout
ListView listView = (ListView) view.findViewById(R.id.listview);
// values is a StringArray holding some string values.
CustomAdapter customAdapter = new CustomAdapter (getActivity(), values);
listView.setAdapter(customAdapter );
Use multi-dimensional array of Radio Button or group or whatever you want...
RadioButton[][] rb = new RadioButton[][];
Use above statement for declaring it and for accessing it use two loops which are nested. One loop is nested in another.
for(int i=0;i<=5;i++)
{
for (int j=0;j<=5;j++)
{
rb[i][j] = new RadioButton(this);
}
}
I am having a table view inside list view.
I want to make the table dynamic. There are fixed 3 columns, but the rows vary in number.
There is a image in each cell. I want that there should be as many table cell as number of images. The number of table rows vary in each row of the list view.
When I create table the image is add to the last cell.
public class BrandView extends LinearLayout {
TableLayout table_layout;
Context context;
Brand brand;
CheckBox chkType,chkName;
TextView txtTypeName,txtBrandName;
ImageView imgBrandImage;
public BrandView(Context context) {
super(context);
this.context=context;
HookUp();
}
public void setBrandView( Brand brand){
this.brand=brand;
imgBrandImage.setImageResource(brand.getImage());
txtTypeName.setText(brand.getTypeName());
}
public void HookUp(){
LayoutInflater inflater=LayoutInflater.from(context);
View view=inflater.inflate(R.layout.lay_brand_select_view,null);
chkType=(CheckBox) view.findViewById(R.id.chkType);
txtTypeName=(TextView) view.findViewById(R.id.txtTypeName);
table_layout=(TableLayout) view.findViewById(R.id.tableLayout1);
BuildTable(1,1);
this.addView(view);
}
private void BuildTable(int rows, int cols) {
// outer for loop
for (int i = 1; i <= rows; i++) {
TableRow row = new TableRow(context);
row.setLayoutParams(new TableRow.LayoutParams(200,
200));
// inner for loop
for (int j = 1; j <= cols; j++) {
LayoutInflater inflater = LayoutInflater.from(context);
View tv = inflater.inflate(R.layout.lay_table, null);
chkName=(CheckBox) tv.findViewById(R.id.chkName);
txtBrandName=(TextView) tv.findViewById(R.id.txtBrandName);
imgBrandImage=(ImageView) tv.findViewById(R.id.imgBrandImage);
row.addView(tv);
}
table_layout.addView(row, new TableLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
/* if(i==rows)
for(int l=k;l>0;l--)
row.removeViewAt(l);*/
}
}
}
You should add rows to your TableView programatically like you do it in BuildTable() method. The point is you need to call this method every time in ListView's adapter getView() method.
I have a ListView where I send data from a database using SimpleCursorAdapter, but I need to have dynamic row layout, because every table can have different number of columns.
Let's say I create TextViews according to the number of columns:
public int getColumnNumbers() {
int i = 0;
cursor = db.rawQuery("PRAGMA table_info("+DATABASE_TABLE_NAME+")", null);
if (cursor.moveToFirst()) {
do {
i++;
} while (cursor.moveToNext());
}
cursor.close();
return i;
}
........
int rowsNumber = getColumnNumbers();
textViews = new TextView[rowsNumber];
for(i = 0; i < rowsNumber; i++) {
textViews[i] = new TextView(this);
textViews[i].setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
What I'm basically looking for, is a way to get these TextViews passed to CursorAdapter's (or other adapter's) argument int[] to
I'm pretty new to this, so I would appreciate any help or advice.
EDIT:
I'm adding my implementation of bindViewmethod, which I made with help of the links provided here, in case someone would have to face similar issue in the future.
#Override
public void bindView(View view, Context context, Cursor cursor) {
int i, count = myHelper.getColumnNumbers();
String[] columnNames = myHelper.getColumnNamesString();
String text;
LinearLayout layout = (LinearLayout) view.findViewById(R.id.linear_layout_horizontal);
for(i = 0; i < (count-1); i++) {
TextView textView = new TextView(context);
textView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1f));
text = cursor.getString(cursor.getColumnIndexOrThrow(columnNames[i+1]));
textView.setText(text);
layout.addView((TextView)textView);
}
}
EDIT 2:
I found out yesterday that the implementation mentioned above works until you need to scroll. After scrolling, ListView gets deformed.
So again, in case someone would like to do something similar, I'm adding my whole Adapter class.
public class DatabaseCursorAdapter extends CursorAdapter {
private DatabaseHelper myHelper;
private int count;
private String[] columnNames;
public DatabaseCursorAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
myHelper = new DatabaseHelper(context);
count = myHelper.getColumnNumbers();
columnNames = myHelper.getColumnNamesString();
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.text_select, parent, false);
LinearLayout layout = (LinearLayout) view.findViewById(R.id.linear_layout_horizontal);
int i;
for(i = 0; i < count; i++) {
TextView textView = new TextView(context);
textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1f));
textView.setTag(Integer.valueOf(i));
layout.addView(textView);
}
return view;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
int i;
String text;
for(i = 0; i < count; i++) {
TextView textView = (TextView) view.findViewWithTag(Integer.valueOf(i));
text = cursor.getString(cursor.getColumnIndexOrThrow(columnNames[i]));
textView.setText(text);
}
}
}
In the and, as it is with most issues, the solution is pretty easy. Technique is almost the same as if you would use a static layout, except instead of using findViewById, you just tag elements of your layout and use findViewWithTag method.
You need to look at good tutorial, a link is
Populating a ListView with a CursorAdapter . The web page has some nice explanations.
Look at TodoCursorAdapter and the bindView method to check which column/data is available from the database. Snippet of code from tutorial:
#Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.tvBody);
// Extract properties from cursor
String body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
// Populate fields with extracted properties
tvBody.setText(body);
}
I think this is a simple code design.
Code in the webpage to populate data onto Listview:
// Find ListView to populate
ListView lvItems = (ListView) findViewById(R.id.lvItems);
// Setup cursor adapter using cursor from last step
TodoCursorAdapter todoAdapter = new TodoCursorAdapter(this, todoCursor);
// Attach cursor adapter to the ListView
lvItems.setAdapter(todoAdapter);
You can implement an ArrayAdapter instead of CursorAdapter. This makes sense if your app is not continually interfacing with the database. The link is Using an ArrayAdapter with ListView . It is the same website.
In this case, look at getView method instead of the similar bindView.
I am fetching some content from an API which I need to show in android app. The content comes in JSON format, which looks something like this:
{
"items": [
{
"catalog_items": [
{
"date": "23-01-2015",
"content": "Trimmer 1 description",
"name": "Trimmer 1"
},
{
"date": "25-01-2015",
"content": "Trimmer 2 description",
"name": "Trimmer 2"
}
.....
.....
],
"item_category": "Trimmer"
},
{
"catalog_items": [
{
"date": "13-08-2014",
"content": "Shirt description here",
"name": "John Player Shirt"
}
],
"item_category": "Shirts"
},
{
"item_category": "Woolen"
}
],
"pages": [
{
"date": "24-01-2015",
"content": "This is some content about page 1",
"name": "Sample Page title 1"
},
{
"date": "26-01-2015",
"content": "This is some content about page 2",
"name": "Sample Page title 2"
}
]
}
I have to create a dashboard in app which is built up in following manner, based upon above JSON data:
Top Menu
=====================
Trimmers (Gridview)
Trimmer1 Trimmer2
Trimmer3 Trimmer4
======================
Shirts (Gridview)
John Players
======================
Pages (Listview)
Page1
Page2
My Dashboard Fragment fetches this JSON. My Dashboard layout is:
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</RelativeLayout>
and My Dashboard Activity looks like this:
public class HomeFragment extends Fragment {
.....
.....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
try {
JSONObject obj = new JSONObject(loadJSONFromAsset("input.json"));
if(obj.has("catagories")) {
JSONArray catag = obj.getJSONArray("items");
for(int i=0; i< catag.length();i++){
JSONObject catitem = catag.getJSONObject(i);
JSONArray posts = catitem.getJSONArray("catalog_items");
for(int j=0;j<posts.length();j++){
JSONObject postitem = posts.getJSONObject(j);
catList.add(postitem.getString("name"));
}
addGridtoLayout(catitem.getString("item_category"),catList);
}
}
} catch (JSONException e){
e.printStackTrace();
}
return rootView;
}
public void addGridtoLayout(String title, ArrayList<String> itemList)
{
RelativeLayout ll = new RelativeLayout(getActivity());
RelativeLayout.LayoutParams parambs = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
ll.setLayoutParams(parambs);
TextView tv = new TextView(getActivity());
tv.setText(title);
tv.setId(R.id.layout1);
RelativeLayout.LayoutParams lay = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
ll.addView(tv, lay);
GridView gridView= new GridView(getActivity());
gridView.setLayoutParams(new GridView.LayoutParams(GridLayout.LayoutParams.MATCH_PARENT, GridLayout.LayoutParams.MATCH_PARENT));
gridView.setNumColumns(GRID_COL_NUM);
gridView.setAdapter(new HomeGridAdapter(getActivity(), itemList));
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.BELOW, tv.getId());
ll.addView(gridView, params);
mainLayout.addView(ll);
}
This is the code only for items (Gridview).
What I am going is basically wrapping each gridview and the title in a relativelayout. And the relative layouts would appear below the former one, starting from first item.
But gridviews are getting stacked over each other and all items are being shown in a single row.
Is there any method so I can define the relativelayouts of each gridview to appear below the previous one? Also, is there any better approach to achieve this? I mean the basic requirement is to generate dynamic number of gridviews. So is generating layout on the fly is only way to do this?
Thanks for reading this long post.
Well, as I mentioned in comment, I made slightly modified code and that works really awesome. So I am going to elaborate what I did. Maybe it could help someone out.
Since I have to generate multiple sectioned Gridviews, I initially thought of generating tables using TableLayout and adding TableRows to it. Each Tablerow would be holding a RelativeView consiting of:
Item's image (from JSON)
Item's name (from JSON)
So, I initially created this code:
HomeFragment.java
public class HomeFragment extends Fragment {
.....
.....
ArrayList<String> itemList;
private JsonHelper jsonHelper;
private static final int GRID_COL_NUM = 3;
TableRow tbh;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container,false);
TableLayout table = (TableLayout) rootView.findViewById(R.id.tableLayout);
table.setStretchAllColumns(true);
table.setShrinkAllColumns(true);
try {
JSONObject obj = new JSONObject(loadJSONFromAsset("input.json"));
if(obj.has("catagories")) {
JSONArray catag = obj.getJSONArray("items");
for(int i=0; i< catag.length();i++){
JSONObject catitem = catag.getJSONObject(i);
JSONArray items = catitem.getJSONArray("catalog_items");
if(items.length() > 0) {
//Add a Grid Title for this category (span=6, full width)
TableRow tbr = addRowTitle(catitem.getString("cat_name"));
table.addView(tbr); //Add this title row to the table
itemList = new ArrayList<>(); //Hold all items for each category
for(int j=0;j<items.length();j++){
JSONObject singleItem = items.getJSONObject(j);
//I am trying to show only 3 items in a row, so add new row after 3
if(j % 3 == 0){
tbh = addRowGrid(); //add new row and repeat so after 3
table.addView(tbh); //Add this to the table, we will fill items below
}
LinearLayout lnr = new LinearLayout(getActivity());
TableRow.LayoutParams params = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT,TableRow.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER; //Center the items
lnr.setLayoutParams(params);
lnr.setOrientation(LinearLayout.VERTICAL); //As per your need. worked for me
//Item's Image
ImageView itemImg = new ImageView(getActivity()); itemImg.setImageResource(R.drawable.ic_communities); //Default icon for item
TextView itemLabel = new TextView(getActivity());
itemLabel.setText(singleItem.getString("name"));
itemLabel.setTypeface(Typeface.SERIF, Typeface.BOLD);
lnr.addView(postImg,params);
lnr.addView(postLabel,params);
tbh.addView(lnr); //Now we have image and content, wrap in linear layout and add to the row.
itemList.add(singleItem.getString("name")); //This step is not needed for now. I just wrote this to use this array for other purposes.
}
//I am all confused at this point if I have really closed all of curly braces. Please confirm
}
}
}
} catch (JSONException e){
e.printStackTrace();
}
return rootView;
}
public TableRow addRowGrid()
{
return new TableRow(getActivity());
}
public TableRow addRowTitle(String titleb)
{
TableRow rowTitle = new TableRow(getActivity());
rowTitle.setGravity(Gravity.CENTER_HORIZONTAL);
// title column/row
TextView title = new TextView(getActivity());
title.setText(titleb);
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
title.setGravity(Gravity.CENTER);
title.setTypeface(Typeface.SERIF, Typeface.BOLD);
TableRow.LayoutParams params = new TableRow.LayoutParams();
params.span = 6;
rowTitle.addView(title, params);
return rowTitle;
}
...
...
}
This whole code works for a single Table layout defined in layout:
fragment_home:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_scrollview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true">
<RelativeLayout
android:id="#+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableLayout
android:id="#+id/tableLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"></TableLayout>
</RelativeLayout>
</ScrollView>
So the whole table is generated on the fly. Worked pretty well. I can attach a click handler to each row to listen, and I might have to set tag for each views to get the clicked item. Its then I thought to more feasible and flexible approach. What if I add the gridview to each row itself, instead of appending LinearLayouts to each TableRows? So, I ended up on modifying my code on this approach:
1. A single TableRow will hold each category title and a second Tablerow will be appended to it, which will hold the gridview.
2. I can now use a Custom Grid Adapter by which I could change layout of each item better, i.e via XML instead of tingling here "on-the-fly" approach.
3. Above point also gained me a clicklistener. So no setting of tag required.
NOTE: The above approach was working as well as below approach is working too (as same). So you can use both
Hence, I create a function that would add title to each category of item and a function to add items to grid, and grid to a row:
HomeFragment.java (gridview version)
public class HomeFragment extends Fragment {
private static final int GRID_COL_NUM = 3;
TableRow tbh;
public HomeFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_home, container, false);
TableLayout table = (TableLayout) rootView.findViewById(R.id.tableLayout);
table.setStretchAllColumns(true);
table.setShrinkAllColumns(true);
try {
JSONObject obj = new JSONObject(loadJSONFromAsset("input.json"));
if(obj.has("catagories")) {
JSONArray catag = obj.getJSONArray("catagories");
for(int i=0; i< catag.length();i++) {
JSONObject catitem = catag.getJSONObject(i);
if (catitem.has("items")) {
JSONArray items = catitem.getJSONArray("catalog_items");
if (items.length() > 0) {
//Add row with title catname
TableRow tbr = addRowTitle(catitem.getString("cat_name")); //Add category Name as title
table.addView(tbr); //Same I did previously
ArrayList<String> itemList = new ArrayList<>();
for (int j = 0; j < items.length(); j++) {
JSONObject singleItem = posts.getJSONObject(j);
itemList.add(singleItem.getString("name"));
}
tbh = addGridRow(itemList); //Create Grid of collections and add it to a tablerow
table.addView(tbh); //Add this tablerow to table
}
}
}
}
if(obj.has("pages")) {
JSONArray pages = obj.getJSONArray("pages");
if(pages.length() > 0) {
TableRow tbr = addRowTitle("Pages");
table.addView(tbr);
ArrayList<String> pageList = new ArrayList<>();
for (int i = 0; i < pages.length(); i++) {
JSONObject page = pages.getJSONObject(i);
pageList.add(page.getString("name"));
}
tbh = addGridRow(pageList);
table.addView(tbh);
}
}
} catch (JSONException e){
e.printStackTrace();
}
return rootView;
}
/**
* Now this is a life saver. Gridviews aren't friendly with scrollviews (I might be wrong, but happens with me everytime), especially if generated dynamically. Hence this function calculates height of each item of gridview dynamically and hence sets the total view height adapted from https://stackoverflow.com/a/22555947/1136491
**/
public void setGridViewHeightBasedOnChildren(GridView gridView, int columns) {
ListAdapter listAdapter = gridView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int items = listAdapter.getCount();
int rows = 0;
View listItem = listAdapter.getView(0, null, gridView);
listItem.measure(0, 0);
totalHeight = listItem.getMeasuredHeight();
float x = 1;
if( items > columns ){
x = items/columns;
rows = (int) (x + 1);
totalHeight *= rows;
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight;
gridView.setLayoutParams(params);
}
public TableRow addGridRow(ArrayList gridItemList)
{
TableRow gridrow = new TableRow(getActivity());
GridView gv = new GridView(getActivity());
TableRow.LayoutParams params = new TableRow.LayoutParams(
TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
gv.setLayoutParams(params);
gv.setNumColumns(GRID_COL_NUM); //3 columns grid
gv.setAdapter(new HomeGridAdapter(getActivity(), gridItemList)); //Custom grid adapter I was talking about. See Below
gridrow.addView(gv);
//Thanks for not messing up my gridview inside scrollview
setGridViewHeightBasedOnChildren(gv,GRID_COL_NUM); //3 Columns
return gridrow;
}
//Simply add title above the gridview
public TableRow addRowTitle(String titleb)
{
TableRow rowTitle = new TableRow(getActivity());
rowTitle.setGravity(Gravity.CENTER_HORIZONTAL);
// title column/row
TextView title = new TextView(getActivity());
title.setText(titleb);
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
title.setGravity(Gravity.CENTER);
title.setTypeface(Typeface.SERIF, Typeface.BOLD);
TableRow.LayoutParams params = new TableRow.LayoutParams();
params.span = 6;
rowTitle.addView(title, params);
return rowTitle;
}
....
}
Now my custom Adapter
HomeGridAdapter.java
public class HomeGridAdapter extends BaseAdapter {
ArrayList<String> result;
Context context;
private static LayoutInflater inflater=null;
public HomeGridAdapter(Context context, ArrayList<String> itemList) {
// TODO Auto-generated constructor stub
this.result=itemList;
this.context=context;
inflater = ( LayoutInflater )context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return result.size();
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public class Holder
{
TextView tv;
ImageView img;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Holder holder=new Holder();
View rowView;
//Layout mentioned below
rowView = inflater.inflate(R.layout.home_grid_layout, null);
holder.tv=(TextView) rowView.findViewById(R.id.textView1);
holder.img=(ImageView) rowView.findViewById(R.id.imageView1);
//Item's Text
holder.tv.setText(result.get(position));
//Item's Image
holder.img.setImageResource(R.drawable.ic_launcher);
//A click listener to each gid item
rowView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(context, "You Clicked "+result.get(position), Toast.LENGTH_SHORT).show();
}
});
return rowView;
}
}
home_grid_layout.xml:
<?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="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_gravity="center"
android:layout_width="88dp"
android:layout_height="88dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:src="#drawable/ic_launcher" />
<TextView
android:id="#+id/textView1"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:text="TextView" />
</LinearLayout>
So I am currently using Gridview version of the TableLayout. I might have achieved what I wanted, but I would really welcome any suggestions here. Hope this answer serves someone a great help.
Thanks for bearing this long.