I am getting data from Database and displaying using a custom list adapter in a ListView. I need to display only even position items in ListView.
i am able to solve this in two ways.
1. sorting data before attaching to adapter, but i want to do those task in getView() method of adapter/by using other available methods in adapter.
2.
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
if( position%2 == 0 ) {
// display
} else {
// not display
}
return view;
in this i am getting alternate view's are empty view's.. i want to avoid these empty view.
i ant to do those all calculations in getView() method, without empty view in the ListView. How i can do this?
I will suggest you to create new List with filtered data and use it in your adapter. Still if you want an alternate solution you can try below code:
#Override
public int getCount() {
int halfCountOfList = itemList.size()/2;
// Add +1 in halfCountOfList if itemList size is odd.
int finalCount = halfCountOfList + itemList.size()%2;
return finalCount;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position*2);
//No need to to check for even item
return view;
}
No, just no. This is a really bad idea.
Don't do this. It makes no sense. Think about it: getView() is called because a View for an item is required. It is too late to make any decision about whether this item needs to be displayed in the ListView or not, it already has to be displayed. What you are trying to do is simply not how ListViews and Adapters are supposed to work.
Just filter the List before passing it to the Adapter, you can modify the List while it is being displayed by exposing it through a getter method on the Adapter and then immediately calling notifyDataSetChanged(). Any other solution which deviates from this or tries to make Adapters work like you expect it would just be a brittle hack and should never be used.
PS: Use a RecyclerView instead of a ListView. It's much better.
If you give a ListView adapter a set of data to display, it's going to try to call getView() on all of the data when it's needed - it doesn't discriminate. The decisions on how to display it are made in the getView() function.
The two are options are to either modify the data set, or only provide full-fledged views to your even index-ed values. Unfortunately, there aren't other ways around this.
Make a another list which contains only even position items in it and pass it on adapter. adapter will call getView method for all items present in list.
make another function in adapter
public int getItemViewType(int position) {
// return a value between 0 and (getViewTypeCount - 1)
return position % 2;
}
After that in GetView() method
int viewType = getItemViewType(position);
switch (viewType) {
case 0:
layoutResource = ;//Even Item
break;
case 1:
layoutResource = ;//Odd Item
break;
}
IF Your data will be of some objectType and the database will return
ArrayList<Object>,
then you can do this
Eg:-
ListView lv; // assign this view to some ListView
final List<Object> listResult; //sorted list returned by database
int len = listResult.size();
for (int i = 1; i <= len; i++) {
if (i % 2 == 0){
Object x = listResult.get(i);
//extract the data you need from the object returned
lv.add(x);
}
}
Related
I have an activity that load messages from internet. Im downloading this to Sqlite, later add this to adapter.
I want to add on screen from a particular number onwards.
We may think we have added 100 items in arrayList adapter. and just we want to show from 75 onwards. SQLite I can add from the last 25, but can not do so because the adapter arrayList must contain all.
I've overwritten getCount () and return 25 to limit the maximum of items, but it does show the first 25 items, not last 25 items.
I think I must do something in getView(). (method override in adapter)
Any ideas?
*************EDIT.ADD SOLUTION
adapter
#Override
public int getCount() {
if(messagesItems.size() <= maxRowsShow){
return messagesItems.size();
}else{
offset = messagesItems.size() - maxRowsShow;
return maxRowsShow;
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
position = position + offset;
...}
I would suggest you do the following.
Get offset of list from where you would like to show list. For eg. 75 from list of 100.
Return offset - list.size() in 'getCount()' of Adapter.
In getView() to get particular item do item = list.get(offset + position)
I have not tried this but maybe you can load all the items in the adapter and then based on their position you can display the one's you need.
I am not sure if this is going to work but atleast you can give it a try.
Thanks
I have searched these forums for nearly 3 hours and seen several similar questions but none of the answers works for me.
I have a single Activity, with several card views. One of the card views has a Spinner with string values and a very simple ListView. The user selects a value from the Spinner, between 1 and 12. The ListView should then display a number of strings equal to the value selected, based on the position in the spinner list. For example, user selects 2nd item in spinner list and the ListView displays 2 strings. I have a custom adapter on the listview. The ListView itself initially displays a single row, which is correct. However, after the user selects a value from the spinner, the listview is not displaying the extra rows, it still only displays one row. The data for the ListView comes from an ArrayList. I have checked the data model of the adapter after the user selects a value and it has the correct number of entries, as does the ArrayList itself, yet no matter what I try the ListView itself still only display the first row. I have tried NotifyDataSetChanged and every variation of Invalidate without success.
The various code samples:
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent == spDoseFrequency){
Toast.makeText(this,String.valueOf(position),Toast.LENGTH_SHORT).show();
rebuildReminderTimesList(position + 1);
}
}
private void rebuildReminderTimesList(int numberOfTimes){
Toast.makeText(this,"yup",Toast.LENGTH_SHORT).show();
//reset selected item to position 1
myApp.iSelectedReminderTimeIndex = 0;
//clear array and list, then rebuild with hourly timeslots
iarrTimes = new int[numberOfTimes][2];
liReminderTimes.clear();
int startTime = 8;
for (int i = 0; i < numberOfTimes; i++){
iarrTimes[i][0] = startTime + i;
iarrTimes[i][1] = 0;
liReminderTimes.add(pad(startTime + i) + ":00");
}
//refresh the listview
myAdapter.notifyDataSetChanged();
}
public class ReminderListAdapter extends ArrayAdapter {
List<String> liTimes;
Context ctx;
LayoutInflater inf;
public ReminderListAdapter(Context ctx, List<String> liTimes) {
super(ctx, R.layout.reminder_time_listview, liTimes);
this.liTimes = liTimes;
this.ctx = ctx;
inf = LayoutInflater.from(ctx);
}
public void setLiTimes(List<String> liTimes){
this.liTimes = liTimes;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder viewHolder;
if (view == null){
view = inf.inflate(R.layout.reminder_time_listview,parent,false);
viewHolder = new ViewHolder();
viewHolder.sTime = (TextView) view.findViewById(R.id.tvTime);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.sTime.setText(liTimes.get(position));
return view;
}
private static class ViewHolder{
TextView sTime;
}
}
Any help would be appreciated as this is driving me crazy.
Quick update to this question: I have just tested supplying the initial list more than one value but even then it only displays the first item. Is there perhaps a problem with using ListView inside a CardView object? All my other cards work fine, only the ListView one fails to display properly.
Also, I have tried amending the code so that instead of changing the number of elements in the list, it just changes the text in the string of the first element and this works fine. So the notifyDataSetChanged appears to be working, but it just won't display more than one item. A quick check of the Adapter.getCount() method also gives the correct number of elements back, but won't display them.
A lot of folks forget to do the notifyDataSetChanged() call, but you've got that. Are you using a custom adapter? If so, that makes this sound like an issue with one or more of the adapter's methods. In particular, it sounds like getCount or getView might not be returning what they should be. That could either be because of a flawed logic issue, the underlying data source isn't being updated correctly, or the underlying data source isn't the same object you think it is. Without seeing your adapter though, it's hard to diagnose.
I found the problem. I had several CardView objects inside a LinearLayout, which itself was inside a ScrollView. As soon as I removed the ScrollView, the List inside the Card displayed properly. This has unfortunately created another problem in that I can no longer scroll the page to see later cards, which I have not yet found a solution for, but that is a different topic.
getItemIdAtPosition() is a function in android used to get the id of an item in a list view given its position
is there any way of doing the reverse, i.e. getting the position of an item is a list view given its id?
No. You have to do it manually. Create a public method inside the adapter you are using; in that method, loop on the adapter items and check each item id. If it is == to the method param, then return the index.
public int getItemPosition(long id)
{
for (int position=0; position<mList.size(); position++)
if (mList.get(position).getId() == id)
return position;
return 0;
}
Update: You might as well save a HashMap for position/id in your adapter, if lookup performance represents a problem for your use case.
Update: If you want to use this method outside the adapter, then use below:
private int getAdapterItemPosition(long id)
{
for (int position=0; position<mListAdapter.getCount(); position++)
if (mListAdapter.get(position).getId() == id)
return position;
return 0;
}
Not sure if the question is still open. Nevertheless, thought I will share how I did it so that it may help someone who is looking to do the same thing.
You can use the tag feature of a view to store the mapping between that view's id and its position in the list.
The documentation for tags on the android developer site explains it well:
http://developer.android.com/reference/android/view/View.html#Tags
http://developer.android.com/reference/android/view/View.html#setTag(int, java.lang.Object)
http://developer.android.com/reference/android/view/View.html#getTag(int)
Example:
In the getView method of your list adapter, you can set the mapping for that view's id and its position in the list, something like:
public View getView (int position, View convertView, ViewGroup parent)
{
if(convertView == null)
{
// create your view by inflating a xml layout resource or instantiating a
// custom view class
}
else
{
// Do whatever you want with the convertView object like
// finding a child view that you want to set some property of,etc.
}
// Here you set the position of the view in the list as its tag
convertView.setTag(convertView.getId(),position);
return convertView;
}
To retrieve the position of the view, you would do something like:
int getItemPosition(View view)
{
return view.getTag(view.getId());
}
A point to be noted is that you do need to have a reference to the View whose position you want to retrieve. How you get hold of the View's reference is dependent on your specific case.
No. Depending on what adapter you're using to back your ListView the id and position may be the same (I haven't looked at all BaseAdapter subclasses so I cannot say for sure). If you look at the source code for ArrayAdapter you will see that getItemId actually returns the position of the object in the adapter. If the position and id are the same, there is no need to use one to get the other. Otherwise you just need to search the adapter for the object your looking for - using either position or id - and you can find the other value.
If what you're talking about is getting objects using some unique key - i.e. one that you define - that can be done. What you need to do is set up your adapter to take a HashMap instead of an ArrayList or regular List of objects. Then you can create your own method to find by key by simply pulling that value from the HashMap.
it's too late to answer but for benefit...
for example if you have listview and you want to get id with click listener you can get it by >>
cListview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
// for id or any informations
itemID = String.valueOf(catList.get(position).getItemID());
// for name or any informations
itemName = String.valueOf(catList.get(position).getItemName());
I know the reason why the getView method of an Adapter is called more than once, but is there a way for knowing which of the returned view will be actually displayed on the activity?
Until now I put all the returned view linked to the same position in a list and, every time I need to modify a shown view I modify all the views corresponding to that position (one of those will be the right one...).
Surely is not the best way...
Here a piece of code of my adapter:
class MyAdapter extends BaseAdapter {
Vector<ImageView> vectorView[] = new Vector<ImageView>[25];
public MyAdapter(Activity context) {
...
}
public doSomeStuffOnAView(int position) {
// needs to know which view corresponds to the given position
// in order to avoid the following for cycle
for (ImageView iv: vector[position]) {
// do something
}
}
public View getView(int position, ...) {
ImageView childView = ...;
if (vector[position]==null) {
vector[position]=new Vector<ImageView>();
}
vector[position].add(childView);
return childView;
}
}
The method getView(...) might be called more than once for each position, but just one returned view per position will be shown on the activity. I need to know which of these. I thought it was the one returned the last time getView has been called for a position, but it is now always true.
one way but it is not standard.. you can directly check with integer variable i.e. hardcoded type. You have list of views in your xml file. jst cross check & compare with integer variable.
Let say I have my view that I use it as a toggle button. When user clicks it, I change the background via setBackgroundResource(). The number of list is around 15 items and ListView can show only around 7 items on screen.
At first, I try to use ListView.getChildAt(position) but when position is more than 7 it returns NullPointer. eventhough ListView.getCount() returns 15. But that's make sense because it show only visible child.
Then I solve it by loop through all Data that binds to this Adapter, change the boolean value, and call notifyDataSetChange()
So the number of loop will be 15 for update data + 7 show visible view.
The best way should be 15 and that's done.
Is there anyway to achieve this?
Thank
Forget your child index. You should just toggle some type of flag in your adapter.
Then when your getView method is called again it will redraw your list.
i.e.:
public class YourAdapter extends BaseAdapter {
private boolean useBackgroundTwo = false;
.. constructor ..
#Override
public View getView (int position, View convertView, ViewGroup parent) {
...
...
View background = findViewById(...);
int backgroundResource = R.drawable.one;
if(useBackgroundTwo){
backgroundResource = R.drawable.two;
}
background.setBackgroundResource(backgroundResource);
....
}
public void useNewBackground(){
this.useBackgroundTwo = true;
notifyDataSetChanged();
}
public void useOldBackground(){
this.useBackgroundTwo = false;
notifyDataSetChanged();
}
}
Then in your activity code:
((YourAdapter) listview.getAdapter()).useNewBackground();
Taking it further, you could use an enum instead of a boolean and have multiple methods setBackgroundGreen(), setBackgroundRed() or you could pass in the drawable you want to use setItemBackground(R.drawable.one); The choice is yours.
Api: Adapter