Android dynamically calculate number of columns - android

I have a dynamically created list of items which should be displayed in either two or one column depending on the space the containing text needs e.g. if the text is long it will only be one item per row, otherwise two. Obviously they should all be the same size (half the screen size).
As far as I know there's no standard Android view with Adapter that does that. With a GridView you can have multiple columns, but not some rows one column and others two. A TableLayout could stretch views, but also here you have to know how many columns you need per row. Plus it doesn't have an Adapter.
So what I want to know a) is there any control that I'm missing that supports something like this or b) what would be the easiest solution for this problem?
EDIT: the items also contain a CheckBox and I need to keep track of the checked state so I can't just put two items in one view using an Adapter.

I'd say that this is a hard problem to solve using standard components, due to the problem of mapping data to items to rows.
If you for example use a Cursor with x rows to feed the adapter with data, then the total item count as seen from the Adapter is also x. However, since you're conditionally mapping two items to the same row, it means that a ListView will see y rows in the Adapter, where y <= x. But you cannot easily tell from the beginning what y will be. Furthermore, if the ListView asks the Adapter for item i where 0 <= i < y, there would be no (easy) way for the Adapter to determine which elements from the Cursor that i would map to.
That being said, a viable solution would be to subclass AdapterView or ListView and implement the layout of the elements yourself. As you're getting each item from the Adapter, you'll measure and layout it, depending on the sizes of the surrounding adapter items.
A different solution that could work for you if you don't have a large number of elements is to use two custom Adapters, one called ItemAdapter and one called RowAdapter. The ItemAdapter will inflate the actual items based on (the presumed) Cursor. The RowAdapter will use the ItemAdapter to get the items and merge them into rows. The ListView will in turn use the RowAdapter. The issue is that to know how many rows the RowAdapter will produce, it is necessary to measure all the items from ItemAdapter before the RowAdapter is connected to the ListView.

As far as I know there is no ready solution for your problem. I haven't yet tried something like this, but I would use a LinearLayout as the list item. Then just create your own Deflater (e.g. CursorAdapter) that deflates the Layout and checks the length. If needed you should be able to add a new View (e.g. TextView) to the LinearLayout.

Related

Android: What’s the best way to implement the BaseAdapter if item content in ListView is dynamic?

In most case, we need to implement the BaseAdapter’s getItemViewType() and getViewTypeCount() for dynamic item content of the listview, as this post says. But I think this solution is only suitable for finite number and knowing beforehand, such as listview item with sending layout and receving layout.
What about the case that the listview with its item content impossible knowing beforehand?
For example, I need to show a contact list from server, the contact list size is about several thousand. For each item, I need to show, for example, the hobby “list”. It is a small range of 0 to tens of string. So in this case:
The item types is relatively bigger than normal case using “getItemViewType”
Though each item may be different, but similar to a certain degree: the item content is different in the number of views, but common in view type. Item A is different from item B only because it have more TextViews.
For each time in the getView, the convertview is hard to simply reuse because they are different, but if we create new TextView and added to the convertView, it will impact the scrolling of the listview. I don't think it's appropriate such way. What should i do in such case?
Unfortunately you cannot easily change the number of item view types on the fly. The getViewTypeCount() method is only invoked when the adapter is set on the ListView. That means, were you to dynamically change it, then you would have to call setAdapter() again. This is a huge performance hit as the ListView will toss out all the recycled views and re-generate everything from scratch again.
Honestly, it looks like you should be using an ExpandableListView instead. It allows you to displays lists of items under groups. The only difference is the groups are placed on top of the list. So where you have A, B, C, D on the left side in your picture...in the ExpandableListView it'll sit on top.
The ExpandableListView can easily handle your situation where a given grouping could have any variable number of items within it. You mentioned needing to store a contact list. I'd suggest taking a look at a RolodexArrayAdapter for use with the ExpandableListView. It may be of help.

Irregular Gridview, first row with one colum, rest id the rows with two columns

I'm trying to implement an irregular gridview for my Android app. I've defined the gridview to show 2 columns but I need to show just 1 column at the first row. Is it possible using a DataAdapter?
I don't think you can accomplish this with a gridview. The adapter simple provides the data, but the view decides how to lay it out. If your requirements allow you to make the number of columns constant, then maybe you can use the gridlayout instead. I'm thinking you could try to do you layout like the google currents app.
Gridview and ListView are super useful if you have 1000's of items since it reuses views as it scrolls. If you have lots a items in your grid, then I would probably try to use the GridView or ListView to accomplish your goal. Maybe you have to get your requirement changed. Another option is to use a ListView, but sub-divide each row into 2 columns.

How to get all children (visible and invisible) from a ListView?

My problem is similar to ListView getChildAt returning null for visible children, but despite searching I cannot find a solution.
I have a ListView with a Scroll. The ListView has 10 items, 7 of which are visible and 3 are hidden by scroll. I also have an external method (out of adapter) that must get all of the children from this ListView (e.g. using getChildAt()).
I need all 10 of the items, but the last 3 are null objects. I've tried code like the following:
getListView().smoothScrollToPosition();
But this doesn't work.
I think that I don't need to post the rest of my code, as the description says everything?
As you have already seen you can't get all the child row views from a ListView simply because a ListView holds only the views for the visible rows(plus some recycled rows but you can't reach those). The correct way to do what you want is to store whatever data in the adapter's data and retrieve it from there.
But the ListView doesn't keep the current values from RadioGroup in
running time.
I've seen that you have some problems with this so I've adapted some old code to build a basic example, code that you can find here.
I don't think so you need to add scroll view for a listView. Scroll automatically works on ListView. Try your application without adding scroll view and I'm sure it'll work as you needed.
The reason those children are null it's because they really do not exist and they will never exist, if only 7 children are on the screen at one time, the system will only create 7 and re-use by passing the convertView back to the adapter getView() method.
If you want to grab information regarding your whole dataset you should search on the dataset itself, instead of the views on the screen. E.g. if it's an ArrayAdapter, loop the array; if it's a CursorAdapter, loop the cursor; etc.
The non-visible children of a listView don't actually exist. When they become visible, one of the redundant views is recycled or a new view is generated. So you can't actually access all the views. Why do you want to? Whatever changes you want to make should be made to the data that populates the views rather than the views themselves.
There are a few point that you need to take care of:
1. List view provides inbuilt scroll functionality, So don't use Scroll view. It will only mess up things.
2. List view doesn't contain ALL the children. When you scroll it, it creates only visible items on run time.
3. If you want to get all the children altogether, Better keep an ArrayList of the child objects that your list has. You can add or remove children to this ArrayList as per requirement.

Does Android have a Table like Adapter for ListView

I'm using a ListView to show a list of items. These items are in a table format with columns and rows. Is there a table like adapter to make sure all the columns and rows line up? I know this brings in the complexity of how large each column should be, what to do with cut off text, and other things. I'm just curious if there is currently and adapter hiding somewhere for this task. Or maybe even another control?
The point of using ListView is to be able to scale to larger data sets by not having to create and layout views for all of the items up-front. Because of this, your request fundamentally conflicts with how ListView works -- ListView simply doesn't know how all of its items will layout, so there is no way for it to automatically make sure they align in some way.
You can ensure they align yourself just by writing the item layout appropriately. For example, very often in the UI you will have an icon followed by a label. If you ensure the icon is a specific size, then all of the list items will align. If you are dealing with elements that are more dynamic like text, you could do the same thing by enforcing up-front a specific width for those elements.
If you really want to have the UI compute the element sizes dynamically and align all of the rows based on them, that is what TableLayout does. It can do this because it always has all elements there to layout together. If you want to allow scrolling in it, you can wrap that in a ScrollView like another poster suggested. Just be aware that this approach will quickly fall apart as your number of rows increases significantly.
I was able to make TableLayout to behave like ListView (at least visually). Here is my answer.
There is GridView for that, but afaik it doesn't work with columns and rows. Luckily you seem to have been expecting some complexity :)
You can use a ListView or a ListFragment and populate items using each time a single TableRow inside a TableLayout (maybe using android:stretchColumns="0")
you'll have a TableLayout per line, so it's probably inefficient but it does what you are trying to do

Should I use multiple ListViews?

I have a RelativeLayout with different elements. I was planning to have two ListViews on it, but I have noticed there are some problems with scrolling. Since each ListView only shows a maximum of 5 rows should I try to make some kind of custom adapter to merge those ListViews? Or is it better to replace the ListView with a LinearLayout/RelativeLayout and add the rows as I get them manually? (like the first answer in here: android listview display all available items without scroll with static header ).
Which should be the proper way on doing this? or is there another way? Also, each row will have an OnClickListener.
There's two solutions if you'd like to keep your list... list-y, without having to prerender all the row Views like the above solution suggests (which can be slow to render, eats RAM and doesn't scale nicely to more than a screen or two of Views, but is a fine quick solution for smaller lists, though I'd just use a bunch of Views in a LinearLayout in a ScrollView rather than a ListView in that case).
Write a custom ListAdapter, overriding getItemViewType, getViewTypeCount and GetView to inflate the proper kind of view and recycle appropriately for your two types of views. You'll also either need to override getItem to contain custom logic for figuring out which set of source data to look in and to map the data accordingly, or mush the data down into one list of Objects (if you're using an arrayadapter) and cast in the getView method (probably a bit slower than handling it in the getItem without casting).
Just use cwac-merge, a view-and-adapter wrapping adapter. You can put two ListAdapters into a MergeAdapter and set that as your single ListView's adapter.
I had problems with scrolling. I never figured out how to have the ListView share vertical space with a different View, and have a single scrollbar for them both.
I worked around it by having everything that needs to scroll on the layout a row in the ListView.
Adding views as rows to a LinearLayout may have problems scaling up, but I think you'll be OK if you only have 10 rows in total. On 1st gen Android devices it'll probably start to get sluggish around 20 items (depends on Layout complexity obviously). ListView scales up by only inflating views as they come on screen.
So in answer to your question either of the two alternatives you suggest will be OK, but the LinearLayout option will be the easiest to code.

Categories

Resources