I want to make a listview that as user scroll to bottom of list view other items of list fill automatically from internet.I wrote code to that in the adapter of that expandable list view (within getGroupView() method)as like this,
public View getGroupView(final int arg0, final boolean arg1, View arg2, ViewGroup arg3) {
//if(arg2==null){
//arg2=act.getLayoutInflater().inflate(R.layout.layout_exlistview_group, null);
}
//((TextView)arg2.findViewById(R.id.nameText)).setText(item.getItemName());
if(arg0>=getGroupCount()-1){//chech is near for end
/*here i run a asynctask to download data and add items to SparseArray of this class.That sparsearray is the source to the adapter to view them in listview*/
}
//return arg2;
}
So is this correct way to do this or is there any good way to do that?
From the fact that you're using getGroupView I assume you're using an ExpandableListView, not a regular ListView, which should probably be stated in your question.
Either way, the best way to do this would be to assign a OnScrollListener onto your list and then do your check there, rather than in getGroupView.
I'd recommend you put something along the lines of the following into your onScroll method:
if (firstVisibleItem + visibleItemCount > (totalItemCount - NUM_BEFORE_LOAD)) {
loadMore()
}
where NUM_BEFORE_LOAD based on your example would be 1, but you could make it anything you want to make the list load quicker than when it hits the bottom.
Related
I have a method that paint the View of selected item but if my ListView has a scroll ( i mean: if my screen can display 9 "lines" - positions - and the total size is bigger than 9 ) and i select one the first nine positions, it will select the position that i choose and one from the last positions ( a position that i need to scroll to see ).
Example: if i select select the position 0 and paint it, the view on position 0 and on position 11 will be painted.
If i try do to:
getListView().getChildAt(int)
And if this position is like '12', it will return null so i'm using the View that i get when onItemLongClick(AdapterView adapterView, View v, int position , long arg3) is called. It looks like that View is based on scroll because i have same View objects for scroll positions.
Here is how i paint the Views:
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View v,
int position , long arg3) {
Log.d("", "");
View tmp = adapterView.getChildAt(position);
int oi = adapterView.getSelectedItemPosition();
if(!mPositions.contains(Integer.valueOf(position))){
v.setBackgroundColor(Color.CYAN);
mViews.add(v);
mPositions.add(Integer.valueOf(position));
} else {
v.setBackgroundColor(Color.TRANSPARENT);
mViews.remove(v);
mPositions.remove(Integer.valueOf(position));
}
return true;
}
});
How can i get distinct views independently if the list is bigger than my screen?
The problem here is that you really shouldn't be modifying the view directly. The whole point of a ListView is that it will create a view for an item, and then potentially use this same view to paint each and every one of the items in the list. (row recycling). It is possible here, that when you modify the background colour of the selected item's view, this view object is then actually being used to draw another row's items - looking like it's just doing it for the wrong row.
What you should do, is create a custom adapter with your own implementation of getView(). Inside this function you will do one of two things: If convertView is null, then create the View that you desire (possibly a TextView?), otherwise you will grab the view from convertView. Finally you will then set this view up however you would like based on it's position in the list. Ie: if it's text, set the value, and then set your background.
To respond to the longpress, simply change your data (mSeleted) and call notifyDataSetChanged() so that the list will redraw based on this new data.
This is a pretty simplistic overview, listviews can get as complicated as you want. There are many examples of how to create a custom listview on the web if you search.
I am trying to do a endless listview with the Commonsware Endless Adapter (https://github.com/commonsguy/cwac-endless), which works fine by default.
What I am trying to do is a basic chat application.
New items should appear at the end and the chat history should be loadable by the endless adapter when the user scrolls to the top.
This by itself is not hard to do. If the ArrayAdapter contains the data s.t. newest items are at position 0, then simply using android:stackFromBottom in the XML declaration of the ListView will put the beginning of the list at the end.
To make sure that the 'load more' inicator is located at the top, I override getItem, getView etc. to provide it with the reversed positions (count-1-position).
My Problem: When the EndlessAdapter adds new data at the end of the List, the "load more" indicator remains visible, causing it to endlessly fetch more data until there is no more to fetch.
Expected is that it loads one batch and the user then needs to scroll down (here:up) to load further elements.
What am I missing?
Personally, I'd consider pull-to-refresh for this scenario, rather than EndlessAdapter.
That being said, if you are seeing additional rows appear, but the pending view is still there, then your modified getView() is not working properly. The additional rows appearing would indicated that notifyDataSetChanged() itself is functioning (otherwise, those rows would not show up). So, if the pending view is still shown, then getView() presumably is returning the pending view (position 0, I'd guess). In fact, I have no idea how you can get a reverse EndlessAdapter to work, as the first row should always be the pending view and should always be loading data, until you run out of data (and, in the case of a chat, that's possibly never the case).
Hence, again, I'd use pull-to-refresh, or you are going to have to switch to a different "endless" scheme that is paying attention to scroll events, rather than just waiting for the pending view to be displayed, as the trigger to fetch more data.
Do not care on notifyDataSetChanged() help.
I implemented an adapter to return Integer.MAX_VALUE as count of elements and especially calculate index in a cache.
Here is some snippet:
<ListView
android:id="#+id/logContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stackFromBottom="true" />
......
logContainer.setOnScrollListener(new OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if ((logAdapter.getCachedCount() - (Integer.MAX_VALUE - firstVisibleItem)) <= LINES_TO_TRIGGER_PRELOAD && !logAdapter.isPreloading()) {
logAdapter.preloadAtBackground();
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
});
class LogAdapter extends BaseAdapter {
private ArrayList<String> logList = new ArrayList<String>();
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView logLineView = new TextView(LogViewDialog.this);
int idx = logList.size() - (Integer.MAX_VALUE - position);
logLineView.setText(logList.get(idx));
return logLineView;
}
.........
What i want to know?
I was little curious about if i can add a footer to an empty ListView in android. I checked the documentation of ListView footer but they haven't mentioned anything related to this. So just wanted to know if it is possible?
Why i need this?
Actually i have edittext(search box) in my application which will accept characters as input from user. On the basis of this entered text i will do some search in DB & display the matching results in the ListView. What i am planning to do is to display a button at the bottom of ListView(something like footer) which will provide a extended search option to user.
Some code for reference :
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
}
#Override
public void afterTextChanged(Editable s)
{
strGuestCardToSerach = s.toString();
if(strGuestCardToSerach.equals(""))
{
if(listview.getFooterViewsCount() > 0)
{
listview.removeFooterView(footerView);
listviewAdapter.notifyDataSetChanged();
}
}
else
{
if(listview.getFooterViewsCount() == 0)
{
footerView = inflater.inflate(R.layout.footer_view_layout, null);
listview.addFooterView(footerView);
listview.setAdapter(recentGuestAdapter);
listviewAdapter.notifyDataSetChanged();
}
}
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3)
{
}
#Edit :
It does work once you have at least one entry in the ListView. So just wanted to understand if at all it is possible to add a Footer to an empty ListView.
Thanks in advance.
I am posting this just in case if anyone is looking for the similar functionality as mine. Answer is NO, you can't add a footer view to an empty ListView. To achieve the similar functionality you will have create your own layout & add it explicitly to the ListView & manage it's state.
Rupesh
I suppose you use a ListAdapter on your ListView? Just add a "footer item" to your ArrayList/ whatever of list items. In the getView method, check if the item is your footer, then set a custom layout on it where you have your buttons or whatever. Just ask if it's not clear what I mean.
To achieve this scenario when list is empty:
Create to adapter and assign them layouts:
when list is not empty assign adapter to it with layouts.
when list is empty assign list a dummy adapter and with one initial value.
donot assign value to dummy layout in getview or give size to dummy view to 0 dp.
so you can achieve this scenario...
ask further i have solve this scenario
public void addFooterView (View v)
Added in API level 1
Add a fixed view to appear at the bottom of the list. If addFooterView is called more than once, the views will appear in the order they were added. Views added using this call can take focus if they want.
Note: When first introduced, this method could only be called before setting the adapter with setAdapter(ListAdapter). Starting with KITKAT, this method may be called at any time. If the ListView's adapter does not extend HeaderViewListAdapter, it will be wrapped with a supporting instance of WrapperListAdapter.
Parameters
v
The view to add.
I have two ListViews (A and B) with items of the same type (a class I created)
When I click on an item from A, it adds this object on B and if I click again it removes it.
Only that when an item is selected, I change its background using view.setBackgroundColor(myColor).
I want to be able to remove the item from list B (it works), but I want also to reset the background color. I can't figure out how to get the view of this item I'm removing.
Any ideas?
There's no guarantee that any specific ListView item will even have a view at any given time. If the item is currently off-screen, then it may not have a view. Since a specific item might not have a view, it might not make any sense to try to get the item's view.
Beyond that, because of the way ListView creates and reuses views, you'll see some odd, undesirable effects if you simply modify the views directly. As the user scrolls through the list, items that become visible will incorrectly end up with the same backgrounds as other items that have fallen outside the visible portion.
I don't know whether what follows is the best way to implement your functionality because I don't know the cost of rebuilding the list after a change. Here's the (probably naive) way I would do this:
Add another boolean member to your data object, something like isInSecondList.
Override getView() in the Adapter. In getView(), set the background to either normal or highlighted depending on the the value of the item's isInSecondList.
When an item is added or removed from the second list, update the data object to reflect the change, then call the Adapter's notifyDataSetChanged().
int position = 0;
listview.setItemChecked(position, true);
View wantedView = adapter.getView(position, null, listview);
Here is what i did
private View oldSelection;
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long arg3) {
highlightSelectdListItem(position);
}
public void highlightSelectdListItem(int position) {
clearPreviousSelection();
View newsItemView = mGridVIew.getChildAt(position);
oldSelection = newsItemView;
newsItemView.setBackgroundColor(Color.GRAY);
}
public void clearPreviousSelection() {
if (oldSelection != null) {
oldSelection.setBackgroundColor(Color.TRANSPARENT);
}
}
I have an Android ListView created with a SimpleAdapter that has more items in it than fit in the screen. After the list has been scrolled, I need to get the position in the data model of the first visible item in the list.
Basically I want a function like: listView.getChildAt(0).getPositionInDataModel().
Adapter has a few functions in it, like getItemId(position) that looked useful; however, the SimpleAdapter implementation just returns the passed in position, not a row id like I'd hoped.
A brute force solution would be to get the View at index 0, and compare it to the view for each item in the adapter. However, there doesn't seem to be an easy way to get the view for a particular position from the adapter.
Anyone have any thoughts?
It's very easy. Just use ListView.getFirstVisiblePosition() + indexYouWant. For instance, to get the position in the adapter of the 2nd child displayed in the ListView, just use getFirstVisiblePosition() + 1.
No need for all the scary stuff shown in the reply above :)
listView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
public void onItemSelected(AdapterView<?> parent,View view, int pos, long id)
{
AisleId= parent.getSelectedItemId();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
In this we will get list item Id parent.getSelectedItemId();
Simply use the getPositionForView(View) (see documentation). The main advantage of this method is it also works with descendant Views of an item.