Display nested lists on Android - android

I need to display a list of A objects (think List<A>). A has the following structure:
class A {
List<B> bList;
List<C> cList;
}
All three lists can be of arbitrary length. bList and cList should be displayed in their entire length in each row of the list of As. Each list is backed by a SQLite cursor. It's a sort of calendar view. The following image illustrates the idea:
Now, I'm wondering what's the best way to achieve this "in the Android way". I tried multiple things:
ListView for A with nested ListViews for B and C: Not recommended, hard to disable the scrolling behaviour of B and C.
ListView for A with LinearLayout for B and C and programmatically adding child views to the LinearLayouts in the Adapter: I have to manage Cursor updates for B and C and adjust the height of the rows myself, lots of view management code in the Adapter where it does not belong.
Composing everything of nested LinearLayouts: Same problem as 2, even more Cursors to deal with.
Maybe there's a different way where I can fully take advantage of existing functionality?
I already had a look at similar questions on StackOverflow. The top two suggestions seem to be:
Spread data over multiple Activities/Fragments: Considered, not an option because not user friendly (in this case).
Use ExpandableListView: Does not seem to be applicable to the data structure, the list of Bs and Cs should be visible from the beginning.

To implement this type of view you need to implement two things.
ListView listView;
IArrayAdapter iArrayAdapter;
Initialize listView with id provided in xml.
Activity.this.runOnUiThread(new Runnable() {
public void run() {
iArrayAdapter = new IArrayAdapter(Activity.this,
R.layout.list_item, "list of items group it from Bean");
listView.setAdapter(iArrayAdapter);
iArrayAdapter.notifyDataSetChanged();
}
});
list_item is another layout which contaion type of display you need to display in list.
IArrayAdapter is class extending ArrayAdapter
public class IArrayAdapter extends ArrayAdapter<IBean> {
private final Activity context;
private final ArrayList<IBean> iBeans;
private int resourceId;
public InboxArrayAdapter(Activity context, int resourceId,
ArrayList<IBean> iBeans) {
super(context, resourceId, inboxBeans);
this.context = context;
this.iBeans = iBeans;
this.resourceId = resourceId;
}
/*
* TO update View
*
* #see android.widget.ArrayAdapter#getView(int, android.view.View,
* android.view.ViewGroup)
*/
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater layoutInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = layoutInflater.inflate(resourceId, null);
final IBean iBean = iBeans.get(position);
final ImageView imageView = (ImageView) rowView
.findViewById(R.id.message);
final TextView rowTxt = (TextView) rowView
.findViewById(R.id.senderName);
final TextView rowTxt1 = (TextView) rowView
.findViewById(R.id.senderMessage);
final TextView rowTxt2 = (TextView) rowView
.findViewById(R.id.senderTime);
final CheckBox check = (CheckBox) rowView.findViewById(R.id.check);
.....set text here.....
return rowView;
}
}
imageView, rowtext, etc are part of layout list_item
ANd IBean is java bean class contain your 5 iTem in a list.
Any item you don't want left it blank.

Related

Android Studio, ListView titles has always a single image in all the titles. Can I reduce the x times to 1 time the copy of the images in code

In Android ListView have always a single image repeated in all the titles. How can I reduce a copying of the images in code from x times to 1 time?
Such as the code given below:
public class Test1 extends AppCompatActivity {
ListView listView;
String[] fruitNames = {"Apple","Orange","Kiwi","Passion","Banana"};
int[] fruitImages = {R.drawable.ic_chevron_right,R.drawable.ic_chevron_right,R.drawable.ic_chevron_right,R.drawable.ic_chevron_right,R.drawable.ic_chevron_right};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
In this code I am copying all the times the same image code, that is:
int[] fruitImages = {R.drawable.ic_chevron_right,R.drawable.ic_chevron_right,R.drawable.ic_chevron_right,R.drawable.ic_chevron_right,R.drawable.ic_chevron_right};
I want to set a number of repeats such as x (times the drawable image). Is it possible somehow?
The GitHub Project is available from LarnTech. In this project, my images are an arrow. I can do this by repeating the things but I am curious if it can be done in a lucid way.
Just pass your fruit array alone in the adapter's constructor and use imageView.setResource(R.drawable.ic_chevron_right) to set the drawable
public class SimpleArrayAdapter extends ArrayAdapter<String> {
private final Context context;
private final String[] fruitNames;
public MySimpleArrayAdapter(Context context, String[] fruitNames) {
super(context, -1, values);
this.context = context;
this. fruitNames = fruitNames;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label);
ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);
textView.setText(fruitNames[position]);//fruitName
imageView.setImageResource(R.drawable.ic_chevron_right); //just set the image in the adapter
return rowView;
}
}
As I can see your github project, the images are different in the array.
But here, all the images are same.
If you don't want to create the array of same images, then you can use just one variable here. Like:
int fruitImage = R.drawable.ic_chevron_right;
and it can be used in getView() of CustomAdapter like
image.setImageResource(fruitImage);
But if you've to use different images in each views then you need to use array or go for ArrayList.

Set visibility for an image within a ListView row

Overview:
I have a ListView with a custom adapter/layout, every time a user adds a new row (which contains a number), I check if that number is the smallest in the list. If so, an image within that row must be set as visible while setting all other row's images as invisible.
Problem:
My ListView does not set any row's image as visible, even though I have the index of the smallest element.
How I'm doing it:
//In MainActivity
private void addProduct(float price) { //User adds product
priceList.add(price); //Add to Float list
adapter.notifyDataSetChanged();
updateView(findMinIndex(priceList)); //Find smallest val indx
}
private void updateView(int index){
View v = listView.getChildAt(index -
listView.getFirstVisiblePosition());
if(v == null)
return;
ImageView checkMark = (ImageView) v.findViewById(R.id.check_mark);
checkMark.setVisibility(View.VISIBLE); //Initially set Invisible
}
Edit, CustomAdapter:
public CustomList(Activity context,
ArrayList<Float> priceList) {
super(context, R.layout.list_single, priceList);
this.context = context;
priceList = priceList;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView = inflater.inflate(R.layout.list_single, null, true);
TextView price = (TextView) rowView.findViewById(R.id.new_price);
ImageView cheapest = (ImageView) rowView.findViewById(R.id.check_mark);
price.setText(priceList.get(position) + "");
return rowView;
}
Thank you
It is your priceList binded with the adapter?
First of all i would put a breakpoint to see if you are getting the right view in the updateView method.
try this way;
Create a Pojo class with imageview and it's state(Visibility) initially set all to invisible
Add your items to the ArrayList of Pojo Class type.
when user enters a new row based on your requirement set visibility state to true or false(visible or invisible) and call notifyDataSetChanged() to the adapter.
Doing this way you can have a easy track of the items.
I got it working :).
Problem is that adapter.notifyDataSetChanged(); is async, so while it's doing that, updateView(findMinIndex(priceList)); runs but doesn't find the new row as it should. Therefore, I add a runnable to the ListView object as so:
adapter.notifyDataSetChanged();
listView.post( new Runnable() {
#Override
public void run() {
updateView(findMinIdx(priceList));
}
});
Now it works perfectly!

which is better to display list of objects using ListView in android

I have a List of Objects(POIs- Point of Interested), and now I want to display them in a `ListView.
And the layout of the each item is a little complex.
For an POI object, I will display its name address distance and picutre(if any) and etc.
After google and search at Stackoverflow, it seems that I can use the ArrayAdapter.
As shown in this examle, I have to create a Adapter which extends ArrayAdapter, for example :
private class POIAdapter extends ArrayAdapter<POI> {
private ArrayList<POI> items;
public POIAdapter(Context context, int textViewResourceId, ArrayList<POI> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
POI o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("Name: "+o.getName()); }
if(bt != null){
bt.setText("Address: "+ o.getAddress());
}
}
return v;
}
}
As you can see, I have to refer to the view elements in this adapter, so I think it is not the best choice because the layout of the POI item may change someday, then I have to change this adapter accordingly.
Then I found the SimpleCursorAdapter which can map columns from a cursor to views in an XML file, but it seems that I have to create my own Cursor.
So I wonder if which is better for implemention and possible extension?
You may want to choose ArrayAdapter if:
If you're using an array to hold the data.
The layout has some logic in it apart from simple mapping of data to UI elements (e.g. some elements are hidden, etc.)
SimpleCursorAdapter may be better if:
You already have a cursor with your data and your layout needs are simple.
It's hard to give a very general guidance as lots depends on exact requirements. Also, think about what you may want to do in the future. ArrayAdapter makes it easier to create complex layouts even if you need to make code changes to achieve that.

Multiple List Views?

I'm trying to display high scores for a game I'm creating, with two columns, one for their name, and the other for the amount of moves it took them to complete the game.
Currently it is all stored in a SQLiteDatabase and presented in a list view, where it appears as one column in the format
name,moves
But I'd like to get the moves on the opposite of the screen, would this require multiple list views or would it require editing of the one list view, or its adapter?
The code currently used is:
datasource = new HighScoreDataSource(this);
datasource.open(); //Open the connection
List<HighScore> values = datasource.getAllHighScores(); //Retrieve all the data
//Using a simple cursor adapted to show the elements
ArrayAdapter<HighScore> adapter = new ArrayAdapter<HighScore>(this, android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
Make a row layout with two TextViews placed the way you want and implement a simple custom ArrayAdapter:
public class CustomAdapter extends ArrayAdapter<HighScore> {
private LayoutInflater inflater;
public CustomAdapter(Context context, int textViewResourceId,
List<HighScore> objects) {
super(context, textViewResourceId, objects);
inflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.new_row_layout, parent, false);
}
HighScore item = getItem(position);
TextView name = (TextView) findViewById(R.id.name_id_textview);
name.setText(/*get the name from the item HighScore object*/);
TextView moves = (TextView) findViewById(R.id.moves_id_textview);
moves.setText(/*get the moves from the item HighScore object*/);
return convertView;
}
}
Another option is to break your List<HighScore> values in a List of HashMaps(containing two entries, one for name and one for moves) and use a SimpleAdapter(with the row layout above).

ListView ArrayAdapter, hiding children inside Row?

I feel a bit stupid as i can't find the answer to this question, which makes me think i'm actually asking the wrong question. However, here goes...
I have a list view, and a listviewitem defined in xml, with a couple of fields, nothing special. All set to visible.
Then I bind to my ListView using a custom ArrayAdapter, and want to hide one of my text views, on row 5. However, it seems to be hiding my TextView on item 0 and item 5. Which is a bit odd? I've simplified the code, to reproduce the problem and hopefully someone will be able to help me...
My Adapter
public class MenuScreenAdapter extends ArrayAdapter<String>
{
private List<String> _items;
private Context _context;
public MenuScreenAdapter(Context context, List<String> items)
{
super(context, R.layout.list_menu_item, items);
_context = context;
_items = items;
}
private MenuScreenAdapter(Context context, int textViewResourceId)
{
super(context, textViewResourceId);
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_menu_item, null);
}
String o = _items.get(position);
if (o != null)
{
TextView tt = (TextView) v.findViewById(R.id.list_menu_item_name);
if (tt != null)
tt.setText(o);
if (position == 5)
tt.setVisibility(View.GONE);
}
return v;
}
}
My Binding Code
// Load everything up that we need
List<String> items = new ArrayList<String>();
items.add("One");
items.add("Two");
items.add("Three");
items.add("Four");
items.add("Five");
items.add("Six");
items.add("Seven");
items.add("Eight");
items.add("Nine");
items.add("Ten");
// Get the ListView, and set it's adapter. The HomeScreenAdapter
// takes care of the rest
ListView homeScreenListView = (ListView) _mainActivity.findViewById(R.id.view_home_list);
homeScreenListView.setOnItemClickListener(ItemSelected);
homeScreenListView.setAdapter(new MenuScreenAdapter(_mainActivity.getBaseContext(), items));
Thanks in advance!
Since row views are reused by ArrayAdapter, once the View.GONE is set, it will cary on to the next row, where this view will be reused. In your case, you set View.GONE to textview in the fifth row, moved list a little and arrayadapter decided to reuse your fifth row layout to display the first row, since no changes were done to it, the textView still remains hidden.
Just do the:
if (position == 5) {
tt.setVisibility(View.GONE);
} else {
tt.setVisibility(View.VISIBLE);
}
P.S. If you still haven't, watch a presentation about ListViews from google. Tons of usefult info there. ListViews

Categories

Resources