i have gridview with two column
user can scroll vertically to see gridview items
the problem is when user scrolling is finished
the first visible row is not completely seen .i want to set top of first visible row to top of gridview so first row is comletely visible
can anyone help me?
Update:
the first item is
and the second item is
but after scroll we see
you can try this
grid.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView arg0, int scrollState) {
//this is the state when scroll finish
if(scrollState==SCROLL_STATE_IDLE)
//the first visible item is the first (even partially) visbile item
//setSelection will scroll the grid to the beginning of such item
grid.setSelection(firstVisibleItem);
}
#Override
public void onScroll(AbsListView arg0, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
I use RecyclerView, and i hope it's good for you!
mLayoutManager = new GridLayoutManager(getActivity(), 2);
mListRV= (RecyclerView).findViewById(R.id.list_rv);
mListRV.setLayoutManager(mLayoutManager);
mListRV.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
View v = mLayoutManager.getChildAt(0);
int offsetTop = v.getTop();
int offsetBottom = v.getBottom();
int height = (offsetBottom - offsetTop);
if(offsetTop >= -height/2) {
mListRV.smoothScrollBy(0, offsetTop);
} else {
mListRV.smoothScrollBy(0, height + offsetTop);
}
}
}
});
With this code, when you finish scroll, if the first visible item only show a part in recyclerView. It will auto scroll to show full item. You can use:
mLayoutManager.scrollToPositionWithOffset(position, offset);
But it is so fast, the user can be confused. And you will not need use customLayoutManager to edit scroll's properties.
Hope that helps for you!
Related
I'm developing a chat application and I'm trying to load 10 messages at a time, and when the user scrolls up it loads 10 more. therefore I used stackFromBottom=true to load the messages from the bottom :
<ListView
android:id="#+id/messagesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:transcriptMode="normal"
android:stackFromBottom="true">
And I have a scroll listener to know when the user reached the top (firstVisibleItem == 0 , i.e the first message) so I can load more messages:
messagesList.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView absListView, int i) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem ==0 && !loading && !startApp) {
loading = true;
skip += 10;
fetchMessages = new FetchMessages(); //load more items
fetchMessages.execute(true);
}
}
});
The issue is when you scroll up and reach the top, 10 more messages load but the Listview automatically scrolls to the bottom. I want to stay in the exact same position when new items are added to the Listview, just like any regular chat application.
This is the add messages method:
#Override
protected void onPostExecute(String json) {
if(json!=null){
...
//After Parse JSON ...
chatMessageAdapter.list.add(0,chatMessage); //add the message to the top of the list
chatMessageAdapter.notifyDataSetChanged(); //listview scrolls to the bottom afterwards
}
loading = false;
startApp = false;
}
I tried many of the suggestions in other threads but none of them actually worked. I hope someone could help here.
Many thanks.
what did work for me was that:
// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// notify dataset changed or re-assign adapter here
// restore the position of listview
mList.setSelectionFromTop(index, top);
Do note you have to remove android:transcriptMode="normal" from your xml, otherwise it wouldn't work.
I'm having an issue with the SwipeRefreshLayout. I have a list view within the layout and every time I scroll upward in the list view the swipe to refresh layout is tiggered and you can never scroll back to the top of the layout. Anyone have any ideas?
I found an answer to my question. I am manually enabling the swipeRefreshLayout when the first child in the listview is at the top of the list.
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView listView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int topRowVerticalPosition = (listView == null || listView.getChildCount() == 0) ?
0 : expandableListview.getChildAt(0).getTop();
refresh.setEnabled((topRowVerticalPosition >= 0));
}
});
https://developer.android.com/reference/android/support/v4/widget/SwipeRefreshLayout.html
According to Android docs at the above link,
This layout should be made the parent of the view that will be refreshed as a result of the gesture and can only support one direct child.
If the ListView is the 1st direct child of the SwipeRefreshLayout, refresh won't be triggered before scrolling back to the top of the ListView. You don't need to do anything in onScroll().
I am building an application like techcrunch.
I am fetching data from server in JSON format and displaying the data in list view like article title,author name and image.
I have applied pagination means when user scroll more articles load in a list view. My pagination works fine but there is an issue in the scroll function as the fresh or new data loads the scroll dose not aligns with the data.
To clarify more in simple words my scroll-er goes at the top of the page when i am actually scrolling down
this is my code :
listView.setOnScrollListener(new AbsListView.OnScrollListener()
{
#Override
public void onScrollStateChanged(AbsListView absListView, int i)
{
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
int lastItem = firstVisibleItem + visibleItemCount;
if(lastItem == totalItemCount){
if (mPreLast != lastItem)
{
mPreLast = lastItem;
onStart();
}
}
}
});`
You can use:
listView.setSelectionFromTop(newPosition, 0);
With this method you can set the position to a ListView, using the first parameter as the new position on the list, and the second parameter can be used to set the distance from the top
I´m trying to create an app inspired in the google play app.
I have my
RelativeLayout
- RelativeLayout: * Header(this is the one that will be hidden when scrolling).
- RelativeLayout
* ListView
When I scroll down I want the header to be pushed up the screen and then my listview will occupy the whole screen and when I scroll up the header will return to its original position.
I am currently using this code, but it flickers when I´m somewhere at the top of the list.
// Hide top relative layout
list.setOnScrollListener(new AbsListView.OnScrollListener() {
int mPosition=0;
int mOffset=0;
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int position = list.getFirstVisiblePosition();
View v = list.getChildAt(0);
int offset = (v == null) ? 0 : v.getTop();
if (mPosition < position || (mPosition == position && mOffset < offset)){
// Scrolled up
overridePendingTransition(R.anim.slide_up, R.anim.slide_down);
headerLayout.setVisibility(View.GONE);
} else {
// Scrolled down
headerLayout.setVisibility(View.VISIBLE);
}
}
});
Can anyone please help me? It will be appreciate. I don't know if I'm using the right layouts.
Thanks in advanced!
I have a listview with a bunch of items of different sizes
I have a button to scroll to a certain item in the listview
however, when this item is last, the listview of course stops when this item becomes visible
but I want the listview to scroll up in such a way that this last item is the only visible item on the screen - and the bottom of the list is blank
how do I do this?
my scroll method:
public void scrollTo(int newPosition) {
lv.smoothScrollToPositionFromTop(newPosition+ 1, 0, 500);
handler.postDelayed(new Runnable() {
#Override
public void run() {
//this is needed in order for the item to be at the top
//because the listview stops, if scrolling from top down, and stops
//once item becomes visible
lv.smoothScrollToPositionFromTop(newPoisition+ 1, 0, 0);
}
}, 501);
}
this is the crash report for adding a dummy item manually
Well, you can do this in the following way:
Detect the end of the list view.
When the list view reached the end, keep the last one in the list(array list that is used to populate the list) and the delete all others and refresh the list. If you do not want to delete them, simply copy to another array list and copy back the items, if the user needs to move up again.
To detect the end of the list view you can use the following class:
public final class GVOnScrollListener implements AbsListView.OnScrollListener {
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
offset++;
}
}
if (!loading && totalItemCount == (firstVisibleItem + visibleItemCount) && (productCount > totalItemCount)) {
productListServiceRequest();
businessResultListView.setSelection(firstVisibleItem);
loading = true;
new Handler().postDelayed(new Runnable() {
public void run() {
readyToRequest = true;
}
}, 2000);
readyToRequest = false;
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
and set it to the list view like:
listview.setAdapter(businessPromotionListAdapter);
With the above class, you can see:
Number of items that you can see in the screen.
Number of items that you have scrolled up.
Total number of items in the list.