How to populate Layout with multiple HorizontalListView - android

I have a horizontal Listview. It works fine. My ArrayList eList will show a ListView going across the screen. That's great. My problem is that eList has multiple rows meaning eList might be planes, cars, and boats, or an infinite number of objects. Currently this Horizontal ListView will show only all the kinds of planes OR cars OR boats in the Database. How do show multiple or an infinite number of hListViews going down the screen vertically based upon how many object types(planes,cars,boats,tacos,people).
IN ACTIVITY
HorizontalListView hListView = (HorizontalListView) findViewById(R.id.hlistview1);
hListView.setAdapter(new ItemAdapter());
ArrayList<HashMap<String, String>> eList = controller.getAllts();
ListAdapter adapter = new SimpleAdapter(Su.this,eList,R.layout.view_m_ts, images, ins);
hListView.setAdapter(adapter);
IN DATABASE
public ArrayList<HashMap<String, String>> getAllts() {
ArrayList<HashMap<String, String>> List3;
List3 = new ArrayList<HashMap<String, String>>();
String selectQuery3 = "SELECT DISTINCT * FROM INV where p2 IS NOT NULL ORDER BY p2 COLLATE NOCASE ASC";
SQLiteDatabase database = this.getWritableDatabase();
Cursor cursor3 = database.rawQuery(selectQuery3, null);
HashMap<String, String> map = new HashMap<String, String>();
if (cursor3.moveToFirst()) {
do {
map.put("iImageL", cursor3.getString(13));
map.put("p2", cursor3.getString(2));
map.put("se2", cursor3.getString(10));
map.put("te", cursor3.getString(17));
List3.add(map);
} while (cursor3.moveToNext());
}
close();
return List3;
}
IN XML
<LinearLayout
android:id="#+id/LinearViewa"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:orientation="vertical" >
<com.devsmart.android.ui.HorizontalListView
android:id="#+id/hlistview1"
android:layout_width="fill_parent"
android:layout_height="10dp"
android:layout_weight=".1"
android:background="#000000" />
</LinearLayout>

I'm going to assume that all objects of different types are in one SQLite table, with the type stored in one of the columns as a string, and you don't have a different table for each type.
Change your getAllts() function to return a HashMap of ArrayLists of HashMaps instead of an ArrayList of HashMaps, so that you can create multiple HorizontalListViews, one for each ArrayList of HashMaps, each one for a particular type. As you iterate through the rows returned in the cursor, get the type and check if there is already an ArrayList for it in your big HashMap, if not then create one and if so then add to the existing one:
public HashMap<String, ArrayList<HashMap<String, String>>> getAllts() {
HashMap<String, ArrayList<HashMap<String, String>>> hashMap = new HashMap<String, ArrayList<HashMap<String, String>>>();
String selectQuery3 = "SELECT DISTINCT * FROM INV where p2 IS NOT NULL ORDER BY p2 COLLATE NOCASE ASC";
SQLiteDatabase database = this.getWritableDatabase();
Cursor cursor3 = database.rawQuery(selectQuery3, null);
int typeColumnIndex = 18; // <- You need to set the correct column here, possibly using cursor3.getColumnIndexOrThrow()
if (cursor3.moveToFirst()) {
do {
// create this HashMap inside the loop because we need a new one each time:
HashMap<String, String> map = new HashMap<String, String>();
ArrayList<HashMap<String, String>> List3;
// get the type of this entry as a string
String typename = cursor3.getString(typeColumnIndex);
// check if there already is an ArrayList for this type:
if(hashMap.containsKey(typename))
{
// get existing ArrayList for this type:
List3 = hashMap.get(typename);
}
else
{
// create new ArrayList for this type:
List3 = new ArrayList<HashMap<String, String>>();
hashMap.put(typename, List3);
}
map.put("iImageL", cursor3.getString(13));
map.put("p2", cursor3.getString(2));
map.put("se2", cursor3.getString(10));
map.put("te", cursor3.getString(17));
List3.add(map);
} while (cursor3.moveToNext());
}
close();
return hashMap;
}
Change your XML so that you have an empty LinearLayout in your activity XML:
<LinearLayout
android:id="#+id/LinearViewa"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:orientation="vertical" >
</LinearLayout>
and create a separate XML for the horizontal list view that you can create multiple times and add to your LinearLayout dynamically, in horiz_listview.xml or something like that. You can set up your own custom layout with the type name as a TextView header etc:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- Add type name here if you like-->
<com.devsmart.android.ui.HorizontalListView
android:id="#+id/hlistview1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#000000" />
</LinearLayout>
Then in your activity, get the massive hash map containing all the ArrayLists and iterate through it creating a HorizontalListView for each one and add it to the LinearLayout:
LinearLayout layout = (LinearLayout)findViewById(R.id.LinearViewa);
HashMap<String, ArrayList<HashMap<String, String>>> eHash = controller.getAllts();
LayoutInflater inflater = getLayoutInflater();
for(Map.Entry<String, ArrayList<HashMap<String, String>>> entry : eHash.entrySet())
{
// get the type name and ArrayList of Hashmaps for this type:
String typename = entry.getKey();
ArrayList<HashMap<String, String>> eList = entry.getValue();
// inflate a horizonal list view and add it to the layout:
View view = inflater.inflate(R.layout.horiz_listview, null, false);
layout.addView(view);
// set up the horizontal list view like before:
HorizontalListView hListView = (HorizontalListView) view.findViewById(R.id.hlistview1);
ListAdapter adapter = new SimpleAdapter(Su.this,eList,R.layout.view_m_ts, images, ins);
hListView.setAdapter(adapter);
}
If you have more HorizontalListViews than you can fit on screen then you might need to wrap your main LinearLayout in a ScrollView, however be warned that you might run into trouble with that, see this question.

Related

Listview repeating information

I am trying to do a listview with 2 database collumn. I succeded but my problem is that only the first information of the database appears in the listview. If i have x data in the database it will show the x rows in the listview with only the first entry.
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map = new HashMap<String, String>();
data = new ArrayList();
Cursor cursor = mydb.rawQuery("SELECT * FROM projeto", null);
if (cursor.moveToFirst()) {
Toast.makeText(getApplicationContext(), "Caminhos:", 3000).show();
data.clear();
do {
data.add(cursor.getString(cursor.getColumnIndex("id_proj")));
data.add(cursor.getString(cursor.getColumnIndex("nome")));
map.put("id", data.get(0).toString());
map.put("nome", data.get(1).toString());
map.put("hora", "17:00");
mylist.add(map);
} while (cursor.moveToNext());
SimpleAdapter resul = new SimpleAdapter(MainActivity.this, mylist,R.layout.list_item,new String[] {"id", "nome", "hora"}, new int[] {R.id.i, R.id.n, R.id.h});
lista.setAdapter(resul);
I see two problems in your code:
You don't clear data (Like said in a previous answer) so you always get the first two values
You always use the same map. Since map is an object you will always modify the same and your list will be fill will one map.
To fix this two points try this:
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
data = new ArrayList();
Cursor cursor = mydb.rawQuery("SELECT * FROM projeto", null);
if (cursor.moveToFirst()) {
Toast.makeText(getApplicationContext(), "Caminhos:", 3000).show();
do {
HashMap<String, String> map = new HashMap<String, String>();
data.clear();
data.add(cursor.getString(cursor.getColumnIndex("id_proj")));
data.add(cursor.getString(cursor.getColumnIndex("nome")));
map.put("id", data.get(0).toString());
map.put("nome", data.get(1).toString());
map.put("hora", "17:00");
mylist.add(map);
} while (cursor.moveToNext());
SimpleAdapter resul = new SimpleAdapter(MainActivity.this, mylist,R.layout.list_item,new String[] {"id", "nome", "hora"}, new int[] {R.id.i, R.id.n, R.id.h});
lista.setAdapter(resul);
look at this,
map.put("id", data.get(0).toString());
map.put("nome", data.get(1).toString());
map.put("hora", "17:00");
You always put the same key in the map, always "id, nome and hora" you need put diferent key.
ps: Why you create a List of Map? You don't need to this.
You need to clear data each time through the loop. You need to move your call to data.clear() to just after the do { loop begins. What you're doing at the moment will mean that after the first item is retrieved from the cursor, data will contain 2 items. After the second time it will contain 4, then 6, etc. You then always read the same two items. If you clear data it should fix your problem.

How to make fragments load faster?

I am currently developing a fragment which contains lists of albums.
The structure is pretty simple:
Horizontal slider contains LinearLayour (horizontal). In order to add an album with songs list I have created a separate view which consists of cover image and a listview. The listview is custom as well where items are linearlayout with 3 textviews. Then I inflate it, populate list, and add to the Horizontal slider.
The issue occurs if I have more than 2 album lists. It takes some time to open a fragment.
Another thing is when I try to scroll (horizontally), sometimes it stops for a short moment, which makes bad user experience.
What I am trying to say is that I have seen similar views and they work quickly and with no lags. Is it possible somehow to optimize it? Or is it possible so that the fragment opens straight away and then the lists load afterwards (kind of lazyload).
LISTVIEW ITEM:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#ccffffff"
android:padding="10dp" >
<TextView
android:id="#+id/album_list_item_number"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:text=""
android:gravity="center|center_vertical"
android:layout_gravity="center|center_vertical"
android:textColor="#333333"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/album_list_item_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:layout_weight="1"
android:gravity="left|center_vertical"
android:layout_gravity="left|center_vertical"
android:textColor="#333333"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/album_list_item_time"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:text=""
android:gravity="center|center_vertical"
android:layout_gravity="center|center_vertical"
android:textColor="#333333"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
POPULATING THE LIST AND ADDING VIEW TO THE HORIZONTAL SLIDER:
View albumView = inflater.inflate(R.layout.artist_album_col, container, false);
//setting cover
ImageView albumCover = (ImageView) albumView.findViewById(R.id.artistAlbumCover);
albumCover.setImageDrawable(getResources().getDrawable(R.drawable.albumcover)); //cover
ListView albumList = (ListView) albumView.findViewById(R.id.artistSongList);
// create the grid item mapping
String[] from = new String[] {"num", "title", "time"};
int[] to = new int[] { R.id.album_list_item_number, R.id.album_list_item_title, R.id.album_list_item_time};
// prepare the list of all records
List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for(int i = 0; i < 24; i++){
HashMap<String, String> map = new HashMap<String, String>();
map.put("num", "" + i);
map.put("title", "title title title title title title title title title " + i);
map.put("time", "time " + i);
fillMaps.add(map);
}
// fill in the grid_item layout
SimpleAdapter adapter = new SimpleAdapter(mContext, fillMaps, R.layout.album_list_item, from, to);
albumList.setAdapter(adapter);
albumContainer.addView(albumView);
You can use Async Task to perform the time-consuming tasks and take them off the UI thread. This will allow the fragment to load quickly and the list to populate "lazily".
Call with:
new LoadingTask().execute("");
And you can stick a class like this in your fragment class (warning! not tested):
private class LoadingTask extends AsyncTask<Void, Void, Void> {
SimpleAdapter adapter;
protected void doInBackground(Void... values) {
// do your work in background thread
// create the grid item mapping
String[] from = new String[] {"num", "title", "time"};
int[] to = new int[] { R.id.album_list_item_number, R.id.album_list_item_title, R.id.album_list_item_time};
// prepare the list of all records
List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for(int i = 0; i < 24; i++){
HashMap<String, String> map = new HashMap<String, String>();
map.put("num", "" + i);
map.put("title", "title title title title title title title title title " + i);
map.put("time", "time " + i);
fillMaps.add(map);
}
// fill in the grid_item layout
adapter = new SimpleAdapter(mContext, fillMaps, R.layout.album_list_item, from, to);
return;
}
protected void onPostExecute(Void value) {
// back in UI thread after task is done
ListView albumList = (ListView) getActivity().findViewById(R.id.artistSongList);
albumList.setAdapter(adapter);
}
}
Another example here.

Change text color inside a ListView

I'm creating a game and here's the code I'm using to show a list of games with the user names, score, date etc. But how do I get the values of the TextViews tv_playerScore and tv_opponentScore so I can compare them and change the textColors of them? Because what I want is to parseInt and see which has the highest value and set its textcolor to green, and the others textcolor to red.
private void showGames(JSONArray games) throws JSONException {
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map = new HashMap<String, String>();
for (int i = 0; i < games.length(); i++) {
map.put("challenger", games.getJSONObject(i).getString("challengerName"));
map.put("active", games.getJSONObject(i).getString("active"));
map.put("opponent", games.getJSONObject(i).getString("opponentName"));
map.put("date", games.getJSONObject(i).getString("date"));
map.put("gameID", games.getJSONObject(i).getString("gameID"));
map.put("amount", games.getJSONObject(i).getString("amount"));
map.put("playerScore", games.getJSONObject(i).getString("challengerScore"));
map.put("opponentScore", games.getJSONObject(i).getString("opponentScore"));
if (Integer.parseInt(games.getJSONObject(i).getString("active")) == 2) {
mylist.add(map);
}
map = new HashMap<String, String>();
}
SimpleAdapter sadapter = new SimpleAdapter(this, mylist, R.layout.list, new String[]
{"amount", "active", "gameID", "challenger", "opponent", "date", "playerScore", "opponentScore"},
new int[] {R.id.tv_amount, R.id.tv_activte, R.id.tv_gameID, R.id.tv_player, R.id.tv_opponent, R.id.tv_date, R.id.tv_playerScore, R.id.tv_opponentScore});
listView.setAdapter(sadapter);
}
If you want to get the values ​​of a textview must use findViewById function from Activity.
TextView tv_playerScore = (TextView) findViewById (R.id.tv_playerScore);
If the showGames() method is not a class that inherits from Activity (or similiar), you should make a setter injection of the elements of sight to those who want to access.
To compare:
tv_playerScore.getText().toString().compareTo(tv_opponentScore.getText().toString());
Finally, to change the color:
tv_playerScore.setTextColor(Color.CYAN);
Regards.
I think you should have a closer look in how ListViews work ( http://developer.android.com/resources/tutorials/views/hello-listview.html )
In short I guess you'll have to write your own Adpater class (e.g. extend SimpleAdapater) and write over its getView method. Here you can set the color of the textviews depending on the according value. (I think it would make sense to have them sorted before instead of checking them every time a list element is drawn...

Get click from button on every row in listview

I generated a ListView as seen below
I don't have enough rep to post images, you'll have to decipher my URL: image
The blue rows in the above image are populated using HashMap:
private void showListView(JSONArray rows, JSONArray totals){
final ListView list = (ListView) findViewById(R.id.historylist);
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map;
String[] titles = new String[]{"recordID","date","description","num1","num2"};
SimpleAdapter mSchedule = null;
try{
for(int i=0;i<rows.length();i++){
map = new HashMap<String, String>();
for(int n=0;n<allRows.getJSONArray(i).length();n++){
map.put(titles[n], allRows.getJSONArray(i).getString(n));
}
mylist.add(map);
}
mSchedule = new SimpleAdapter(
History.this,
mylist,
R.layout.history_row,
titles,
new int[] {R.id.textView0, R.id.textView1, R.id.textView2, R.id.textView3, R.id.textView4}
);
list.setAdapter(mSchedule);
}catch(Exception e){
Log.e("Creating ListView", e.toString());
}
}
<LinearLayout >
<LinearLayout >
<LinearLayout >
<TextView (recordID) />
<TextView (date) />
<TextView (num1) />
<TextView (num2) />
</LinearLayout>
<TextView (description) />
</LinearLayout>
<LinearLayout (When this one is clicked) >
<ImageView />
</LinearLayout>
When the green button in the above image is clicked, Id like to get the blue row information.
(date, description, num1, num2)
Also, if you think there's a better way to populate the ListView, please let me know.
You will need to implement your own custom adapter by extending BaseAdapter. In the getView method you'll need to bind to that Button's click event. I suggest having one instance of OnClickListener and using AdapterView#getPositionForView. Once you have the position for the view holding the button that was clicked then you can get to your data. Either via Adapter#getItem or directly from your data source.

Android setcolour listview particular row (only one particular row)

I want to set color for particular row in listview.That row will know at runtime. I ahve done list view like this :
ArrayList<SalesRoutes> routeList = getSalesRoute();
ArrayList<HashMap<String, String>> routhPath = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < routeList.size(); i++) {
if(Integer.parseInt(routeList.get(i).getOutlets()) >0){
HashMap<String, String> map = new HashMap<String, String>();
map.put("routeCode",((SalesRoutes) routeList.get(i)).getRouteCode());
map.put("routeName",((SalesRoutes) routeList.get(i)).getDescription());
map.put("outlets", ((SalesRoutes) routeList.get(i)).getOutlets());
routhPath.add(map);
}
}
ListView list = getListView();
sd = new SimpleAdapter(this, routhPath, R.layout.route_path,new String[] {"routeCode","routeName","outlets" },new int[] { R.id.routeCode,R.id.routeName,R.id.outlets});
row = getLayoutInflater().inflate(R.layout.route_path_row, null, false);
getListView().addHeaderView(row);
list.setAdapter(sd);
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
list.setSelected(true);
//list.setSelection(0);
list.setTextFilterEnabled(true);
list.setItemsCanFocus(true);
list.setItemChecked(positions, true);
list.setSelectionAfterHeaderView();
Please tell me how can i do this...
Thanks in advance
One way is to use the index of the row you want to get like
getListView().getChildAt(index).setBackground(#ff0000);
Otherwise you would need to create a custom adapter and overwrite the getView method which is called before rendering each row. You can use that to check any conditions and set the background accordingly.
http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
The above is a tutorial about that.

Categories

Resources