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.
Related
I am trying to make list view in android .I am able to make simple list view using static data .Now I take json file in asset folder . Then I read contend from json file and display on list view .It is working fine.
I do like this
public class MainActivity extends Activity {
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list_view);
Log.d("==", loadJSONFromAsset());
String arr[];
try {
JSONArray js = new JSONArray(loadJSONFromAsset());
arr = new String[js.length()];
for (int i = 0; i < js.length(); i++) {
JSONObject obj = js.getJSONObject(i);
arr[i] = obj.getString("name");
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,arr);
listView.setAdapter(adapter);
} catch (JSONException e) {
e.printStackTrace();
}
}
public String loadJSONFromAsset() {
String json = null;
try {
InputStream is = getAssets().open("data.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
json = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return json;
}
}
It is working fine
But I need to do different task .I need to read json file from asset folder . and create as same number of column as in json array
This is new json file
{"coulmns":[
{
"name": "Test_1"
},
{
"name": "Test_2"
},
{
"name": "Test_3"
},
{
"name": "Test_4"
}
]}
I need to create four column of equal width (because there is four object).If it is three than it show three column of equal width .can we do in android ?
any idea..?
how to do with grid view ?
A GridView is a specific type of ListView that is designed to put your list into multiple columns, or a grid. It's just as easy to use as a ListView, except that you need to specify the number of columns you have. Try this:
Replace the instance of ListView in your XML file with GridView
Replace the ListView in your activity with GridView
Set the number of columns you want. You can make this dynamic by changing it depending on your data.
public class MainActivity extends Activity {
GridView gridView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = (ListView) findViewById(R.id.grid_view);
Log.d("==", loadJSONFromAsset());
String arr[];
try {
JSONArray js = new JSONArray(loadJSONFromAsset());
arr = new String[js.length()];
for (int i = 0; i < js.length(); i++) {
JSONObject obj = js.getJSONObject(i);
arr[i] = obj.getString("name");
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,arr);
gridView.setAdapter(adapter);
gridview.setNumColumns(4);
//You can replace 4 with a formula if you want it to be variable
} catch (JSONException e) {
e.printStackTrace();
}
}
Also see: http://developer.android.com/reference/android/widget/GridView.html
Straight out of the box, the ArrayAdapter<MyObject> is going to populate only a TextView with values as defined by myObject.toString(). If you need a mode complex list item view you have to create your own adapter that extends ArrayAdapter and override getView(...).
For example, your adapter creation would be:
MyArrayAdapter adapter = new MyArrayAdapter(this,R.layout.my_list_item,arr);
I defined MyObject inside the adapter, but it could anywhere. The idea is that MyObject will consist of the texts from one "row" (all the column values)
A very raw version of your adapter could be:
public class MyArrayAdapter extends ArrayAdapter<MyArrayAdapter.MyObject> {
public MyArrayAdapter(Context context, int resource, ArrayList<MyObject> objects) {
super(context, resource, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null)
{
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item, parent, false);
viewHolder = new ViewHolder();
for (int i= 0; i < MyObject.MAX_COLUMNS; i++)
viewHolder.mTextViews[i] = (TextView)((ViewGroup)convertView).getChildAt(i);
convertView.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolder)convertView.getTag();
}
MyObject myObject = getItem(position);
for (int i = 0; i < myObject.myTexts.length; i++)
{
viewHolder.mTextViews[i].setVisibility(View.VISIBLE);
viewHolder.mTextViews[i].setText(myObject.myTexts[i]);
}
for (int i = myObject.myTexts.length; i < MyObject.MAX_COLUMNS; i++)
viewHolder.mTextViews[i].setVisibility(View.GONE);
return convertView;
}
private static class ViewHolder {
public TextView[] mTextViews = new TextView[MyObject.MAX_COLUMNS];
}
public static class MyObject {
public static int MAX_COLUMNS = 4;
public MyObject(String[] texts) {
myTexts = texts;
}
public String[] myTexts;
}
}
And your item layout (with four TextViews, but add/remove if your max columns is different):
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<TextView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>
In case you don't have a way to know the max number of your columns, you have to construct the item layout dynamically instead of inflating it from a resource and more importantly the ViewHolder pattern is pretty much useless.
When a user enters a word, it creates Buttons - one Button per letter of the word:
Illustration:
If the user enters "so" it creates 2 Buttons - 's', 'o'
If the user enters "make" it creates 4 Buttons - 'm', 'a', 'k', 'e'
I was having a hard time deciding how I should design this. Ultimately I decided to do the following: Each word is added to a vertical LinearLayout. And for each word, each letter is added to a horizontal LinearLayout. So it's a LinearLayout within a LinearLayout approach.
Here's the code I created which works:
//creates words dynamically
public void makeNewWord(LinearLayout ll, View v, EditText e){
//the horizontal linear layout
LinearLayout linearLayout2 = new LinearLayout(v.getContext());
linearLayout2.setOrientation(LinearLayout.HORIZONTAL);
//the parameters for the horizontal linear layout
LinearLayout.LayoutParams rlp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
//e is the user input
int size = e.getText().toString().length();
for (int i=0; i<size; i++){
final Button dynamicButtons = new Button(v.getContext());
dynamicButtons.setLayoutParams(rlp);
//add the buttons to the horizontal linear layout
linearLayout2.addView(dynamicButtons, rlp);
}
// ll is the vertical linear layout which I created in xml
// so for each entered word, I am adding horizontal linear layouts to my vertical layout
ll.addView(linearLayout2, 0);
}
But now I realized it's probably more efficient using a ListView, especially since I want to make the list of words to be expandable and collapsible. But Is it possible to create the above illustration using a ListView? How would I go about doing so?
I tried creating an ArrayAdapter as follows: ArrayAdapter<LinearLayout> adapter = new ArrayAdapter<LinearLayout>(this, R.id.listview). So basically it would be a ListView of horizontal LinearLayouts. Or should I make an ArrayAdapter of Buttons instead? What is the correct approach?
I can give some idea you can transform this idea in code
1. onTextChanged() method try to get length of text.
2. If you able to get text length then by subString() method get last entered text
3. Then recreate new button instance
You can use a TableLayout for this.
test.xml
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<TableLayout
android:id="#+id/table_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</TableLayout>
</ScrollView>
Activity Code
private TableLayout tableLayout;
private HashMap<String, TableRow> tableRows;
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.test);
super.onCreate(savedInstanceState);
tableLayout = (TableLayout) findViewById(R.id.table_layout);
tableRows = new HashMap<String, TableRow>();
}
public void addWord(String word) {
if (!tableRows.containsKey(word)) {
TableRow tableRow = new TableRow(this);
for (int i = 0; i < word.length(); i++) {
String letter = String.valueOf(word.charAt(i));
Button btnLetter = new Button(this);
btnLetter.setText(letter);
tableRow.addView(btnLetter);
}
tableRows.put(word, tableRow);
tableLayout.addView(tableRow);
}
}
public void removeWord(String word) {
TableRow tableRow = tableRows.remove(word);
if (tableRow != null) {
tableLayout.removeView(tableRow);
}
}
public void showWord(String word) {
TableRow tableRow = tableRows.get(word);
if (tableRow != null) {
tableRow.setVisibility(View.VISIBLE);
}
}
public void hideWord(String word) {
TableRow tableRow = tableRows.get(word);
if (tableRow != null) {
tableRow.setVisibility(View.GONE);
}
}
Assuming you want a specific button setup, you can inflate an xml button layout dynamically. See here for details.
I would just use a horizontal list view per word.
I you want to be fancy you create a custom layout manager and the new RecyclerView.
Each character of your word would be then a item in your list view. The layout then could be simply a button.
class ListAdapter extends BaseAdapter {
private final Context fContext;
private String mWord;
public ListAdapter(Context context) {
fContext = context;
}
public void updateWord(String word) {
mWord = word;
notifyDataSetChanged();
}
#Override
public int getCount() {
return mWord == null ? 0 : mWord.length();
}
#Override
public String getItem(int position) {
return String.valueOf(mWord.charAt(position));
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Button button;
if (convertView == null) {
button = new Button(parent.getContext());
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
button.setLayoutParams(params);
} else {
button = (Button) convertView;
}
button.setText(getItem(position));
return button;
}
}
On every text change you can then just update the list.
adapter.updateWord();
Be aware the code is just out of my head and i haven't tested this, but should be enough to give you and idea.
I am totally confuse with my image list view.
I want to display 2 video poster and text view in a single row with background container ( check attach image of train)
This is single cell of vertical List view.
Depending on number of videos i have to display vertical list view but each row contain 2 video poster and text view at side of it video with train Engine image at start or end vice versa of row number.
To achieve this UI i write a custom adaptor in which i manage to display train wagon with related image-view by using relative layout.
but how can i manage on-click listener on particular item (particular video in row) on single row.and how can i add train image at start or end of each row
here is output of my code.
Here is my code
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
final Context context = CustomAdapterExample.this;
ListView ls2 = new ListView(context);
// clear previous results in the LV
ls2.setAdapter(null);
// populate
ArrayList<Device> videos = new ArrayList<Device>();
Device my_video;
for (int i=0;i<05;i++) {
my_video = new Device("video link","Video id");
videos.add(my_video);
}
CustomAdapter lvAdapter = new CustomAdapter(context, videos);
ls2.setAdapter(lvAdapter);
ls2.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3)
{
Toast.makeText(getBaseContext(), "You clicked on "+arg2, Toast.LENGTH_LONG).show();
}
});
setContentView(ls2);
}
And here is adaptor
class CustomAdapterView extends LinearLayout {
public CustomAdapterView(Context context, Device device)
{
super( context );
//container is a horizontal layer
setOrientation(LinearLayout.HORIZONTAL);
setPadding(0, 6, 0, 6);
LinearLayout Mainview = new LinearLayout(context);
LinearLayout.LayoutParams Cellparams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Mainview.setLayoutParams(Cellparams);
ImageView firstImageContainer = new ImageView(context);
ImageView trackImage = new ImageView(context);
ImageView VideoViewContainer = new ImageView(context);
TextView firsttext= new TextView(context);
firsttext.setText("Testing of app");
firsttext.setTextColor(Color.RED);
firstImageContainer.setBackgroundResource(R.drawable.wagon);
VideoViewContainer.setBackgroundResource(R.drawable.video);
RelativeLayout layout = new RelativeLayout(context);
RelativeLayout.LayoutParams firstContainerParams = new RelativeLayout.LayoutParams(160, 80);
layout.setLayoutParams(firstContainerParams);
trackImage.setBackgroundResource(R.drawable.line);
RelativeLayout.LayoutParams trackRules = new RelativeLayout.LayoutParams(755,5);
trackRules.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
RelativeLayout.LayoutParams firstImageContainerParams = new RelativeLayout.LayoutParams(140, 90);
RelativeLayout.LayoutParams VideoViewContainerParams = new RelativeLayout.LayoutParams(70,60);
VideoViewContainerParams.addRule(RelativeLayout.CENTER_VERTICAL);
VideoViewContainerParams.setMargins(5, 0, 0, 0);
layout.addView(firstImageContainer, firstImageContainerParams);
layout.addView(VideoViewContainer, VideoViewContainerParams);
layout.addView(trackImage, trackRules);
ImageView secondImageContainer = new ImageView(context);
ImageView secondtrackImage = new ImageView(context);
ImageView secondVideoViewContainer = new ImageView(context);
secondImageContainer.setBackgroundResource(R.drawable.wagon);
secondVideoViewContainer.setBackgroundResource(R.drawable.video);
RelativeLayout secondLayout = new RelativeLayout(context);
RelativeLayout.LayoutParams secondContainerParams = new RelativeLayout.LayoutParams(160, 80);
secondLayout.setLayoutParams(firstContainerParams);
secondtrackImage.setBackgroundResource(R.drawable.line);
RelativeLayout.LayoutParams secondtrackRules = new RelativeLayout.LayoutParams(755,5);
trackRules.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
RelativeLayout.LayoutParams secondImageContainerParams = new RelativeLayout.LayoutParams(140, 90);
RelativeLayout.LayoutParams secondVideoViewContainerParams = new RelativeLayout.LayoutParams(70,60);
secondVideoViewContainerParams.addRule(RelativeLayout.CENTER_VERTICAL);
secondVideoViewContainerParams.setMargins(5, 0, 0, 0);
secondLayout.addView(secondImageContainer, secondImageContainerParams);
secondLayout.addView(secondVideoViewContainer, secondVideoViewContainerParams);
secondLayout.addView(secondtrackImage, secondtrackRules);
firstContainerParams.addRule(RelativeLayout.ALIGN_LEFT);
secondImageContainerParams.addRule(RelativeLayout.ALIGN_RIGHT);
Mainview.addView(layout,firstContainerParams);
Mainview.addView(secondLayout,secondContainerParams);
addView(Mainview);
}
}
public class CustomAdapter extends BaseAdapter /*implements OnClickListener*/ {
public static final String LOG_TAG = "BI::CA";
private Context context;
private List<videoData> videolist;
public CustomAdapter(Context context, List<Device> videolist ) {
this.context = context;
this.videolist = videolist;
}
public int getCount() {
return videolist.size();
}
public Object getItem(int position) {
return videolist.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
Device device = videolist.get(position);
View v = new CustomAdapterView(this.context, device );
return v;
}
}
If my implementation is wrong than please suggest me some guidance.
gallery is deprecated in API 17 i can't use it.
Is it possible to crate such Ui by using tableview or grid view??
Any Help is Appreciated.
Finally I figure it to display All contain same as on other device by using Include tag in list view layout.
<HorizontalScrollView
android:id="#+id/horizontalScrollView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<include android:id="#+id/train2" layout="#layout/train2" />
</HorizontalScrollView>
In train I have this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<include android:id="#+id/boogi1" layout="#layout/boogi" />
<include android:id="#+id/boogi2" layout="#layout/boogi" />
<include android:id="#+id/engine" layout="#layout/engine" />
And to access each Image-view and textview i used
ImageView v1 = ((ImageView)vi.findViewById(R.id.train).findViewById(R.id.boogi1).findViewById(R.id.imageView1));
Thank you for support.
Just one question is it possible to change view for every row depending on position of row..
I think you need to try Custom Listview,,,
try this http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/.
At the moment I am getting items out of my database and add them to a string called result which I return and set to my TextView:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.level);
loadDataBase();
int level = Integer.parseInt(getIntent().getExtras().getString("level"));
questions = new ArrayList<Question>();
questions = myDbHelper.getQuestionsLevel(level);
tvQuestion = (TextView) findViewById(R.id.tvQuestion);
i = 0;
String data = getAllItems();
tvQuestion.setText(data);
}
private String getAllItems() {
result = "";
for (i = 0; i<9; i++){
result = result + questions.get(i).getQuestion() + "\n";
}
return result;
// TODO Auto-generated method stub
}
The thing is, all these items also have a title(string) and graphical thumb (string) in the database. I would like to show them as illustrated in the picture below, each with an onclicklistener on it, instead of a boring list of items below eachother. Each item has a picture and title.
Since my beginning programming skills, I am wondering how to do this best, and if you know any good tutorials on it which explain it well?
Thanks!
if i understood your question you need to create a customize an adapter.
Create a new simple class like this which holds an string and a picture
Class ObjectHolder {
int Image;
String Title;
}
and create a getter and setter for this two
then create custom ArrayAdapter
Class CustomArrayAdapter extends ArrayAdapter<ObjectHolder> {
public CustomArrayAdapter(Context C, ObjectHolder[] Arr) {
super(C, R.layout.caa_xml, Arr);
}
#Override
public View getView(int position, View v, ViewGroup parent)
{
View mView = v ;
if(mView == null){
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = vi.inflate(R.layout.cpa_xml, null);
}
TextView text = (TextView) mView.findViewById(R.id.tv_caarow);
ImageView image = (ImageView) mView.findViewById(R.id.iv_caarow);
if(mView != null )
{ text.setText(getItem(position).getText());
image.setImageResource(getItem(position).getImage());
return mView;
}
}
and create caa_xml.xml in res\layout\
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/iv_caarow"
android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tv_caarow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="15dip"
android:layout_BottomOf="#+id/iv_caarow" />
</RelativeLayout>
and use it like this.
GridView GV= (GridView) findViewById(R.Id.gv); // reference to xml or create in java
ObjectHolder[] OHA;
// assign your array, any ways!
mAdapter CustomArrayAdapter= CustomArrayAdapter(this, OHA);
GridView.setAdapter(mAdapter);
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);
}