How can I maintain the scroll position of a GridView (it's filled with search results) throughout a screen reorientation?
I have the GridView inside a Fragment, and when I rotate the screen it jumps back up to the top of the list.
To make it even more tricky, in landscape mode my GridView has 3 columns.. in portrait mode it has 2 columns.
I can't seem to figure out how to keep the fragment's GridView scrolled to anywhere near where it should be when the screen orientation changes.
You can use the following method, it will work for all Android versions.
To save the current scrolling position:
int index = gridView.getFirstVisiblePosition();
Then after orientation change, use the following code to set the gridView position to the saved index:
gridView.setSelection(index);
You can try this:
Initially you have to get the current scrolling position of the GridView by calling:
int index = gridview.getFirstVisiblePosition();
Then you have to save this value while orientation changes and when the GridView is created again you have to move your gridview to this index.
I suppose this could work:
gridview.smoothScrollToPosition(int index)
Hope this helps!
Using of getFirstVisiblePosition() is good, but I've found a nice solution, just to save a state of view.
//state of view (includes scroll position) as a Parceble
Parcelable mobileGalleryState = gridView.onSaveInstanceState();
//just restore previous state including all changes are made before
gridView.onRestoreInstanceState(mobileGalleryState);
By the way, you can use it for ListView also.
Related
I have implemented a horizontal recyclerView with LinearSnapHelper, to implement a UI input that selects a particular configuration. Kinda like the old school number picker/selector or spinner. The item in the center is the selected position.
it works fine and all, but here's the problem. On initial start up, I need to programmatically set the position of the recycler view such that the selected item (the index of which was loaded from disk) is position in the center.
.scrollToPosition() wont work becuase it places the selected item in the begining.
now I know I can do all the math and calculate the x coordinate and manually set it, but thats a lot of redundant work because LinearSnapHelper is already doing this, and I feel like there should be a way to just reuse that logic, but with actually initiating a fling.
I need something like LinearSnapHelper.snapToPosition()
More general solution:
First scroll RecyclerView to make target item visible.
Than, take the object of target View and use SnapHelper to determine
distance for the final snap.
Finally scroll to target position.
NOTE: This works only because programmatically you are scrolling at the exact position & covering the missing distance by exact value using scrollBy instead of doing smooth scrolling
Code snippet:
mRecyclerView.scrollToPosition(selectedPosition);
mRecyclerView.post(() -> {
View view = mLayoutManager.findViewByPosition(selectedPosition);
if (view == null) {
Log.e(WingPickerView.class.getSimpleName(), "Cant find target View for initial Snap");
return;
}
int[] snapDistance = mSnapHelper.calculateDistanceToFinalSnap(mLayoutManager, view);
if (snapDistance[0] != 0 || snapDistance[1] != 0) {
mRecyclerView.scrollBy(snapDistance[0], snapDistance[1]);
}
}
});
Try calling smoothScrollToPosition on the RecyclerView object, and passing the position index (int)
mRecyclerView.smoothScrollToPosition(position);
Worked for me with a LinearLayoutManager and LinearSnapHelper. It animates the initial scroll, but at least snaps the item in position.
This is my first post on the stack, hope it helps :)
I have a recyclerView which I have added padding at the left and right with dummy views in the adapter. So that the first "actual" item can be snapped to.
I couldn't get smoothScrollToPosition(0) to work though for the initial snap. I used the following
recycler.scrollBy(snapHelper.calculateDistanceToFinalSnap(binding.recycler.getLayoutManager(), recycler.getChildAt(1))[0], 0);
Isn't the nicest looking way, but seems to work!
I have TextView+webview as ListItem of ListView. When I change orientation. I am reloading all files as well setting adapter again and I am calling following code to select item from list programtically so I can get onItemClick call same ways as user would have clicked.
if(position!=-1 && getAdapter()!=null){
requestFocusFromTouch();
performItemClick(
getAdapter().getView(position,
null, null), position,
getAdapter().getItemId(position));
}
Now when I change orientation of screen, the selected item's webview is not scrolling till the end. It seems that it is not changing its scrolled position when we change orientation (Even though we reset adapter).
I tried requestlayout(), forcelayout(), invalidate(),reload() method of webview but none of them seems to be working.
You probably have your WebViews heights set to wrap_contents. This means that their heights are 0 when the list is loaded and they expand to a > 0 height at some point. One way to solve your issue would be to wait for all of the webviews to call onSizeChanged before scrolling, another option would be to re-position the list every time the lists contents change size.
I have a Gallery object that scrolls from left to right and back again. However, I would like to make this Gallery circle back on itself, that way when I get to my last View, the very first one is next and I can just keep scrolling. Any ideas? Thanks.
Galleries use an Adapter to back the data that they display. You can create a custom adapter where getCount() returns Integer.MAX_VALUE and getView() does a modulos the position with the number of images you have. This way it always returns the appropriate image for a given position.
It seems like ListView doesn't expose its y-position in the same way a ScrollView does. In other words: I need to remember the exact position the ListView was scrolled to and set it when I return to the activity.
Just to clarify: I don't need the selected item... that's pretty straight forward. I need to restore the exact pixel-wise y position on the ListView.
Thanks!
I've used this successfully when saving (in onSaveInstanceState) and restoring (onCreate), when switching orientations:
Saving:
int savedPosition = list.getFirstVisiblePosition();
View firstVisibleView = list.getChildAt(0);
int savedListTop = (firstVisibleView == null) ? 0 : firstVisibleView.getTop();
Restoring:
if (savedPosition >= 0) { //initialized to -1
list.setSelectionFromTop(savedPosition, savedListTop);
}
This will precisely save the Y position. Well, it misses by a few pixels every once in a while.
When you are returning from another Activity, the ListView will remain scrolled to its original position that it was at when you left that ListView Activity. If you are updating the contents of the list make sure you just use notifyDataSetChanged() on the adapter, do not re-assign the adapter - this will reset the list to the top.
Check your onResume method in your ListView Activity, it might be re-assigning a list adapter.
If you need to remember an arbitrary scroll position that doesn't rely on the Activity stack, I am willing to bet that isn't possible besides just saving the current selected or first visible item. A ListView does not have a defined height. It is relative to both the number of items and content of those items.
Parcelable state = list.onSaveInstanceState();
// do stuff
list.onRestoreInstanceState(state);
Is the only correct way I know of to maintain exact position of a list. The above solution that's marked as correct bumps up/down a few pixels so not really the most professional solution.
I have a Gallery view created with a SimpleAdapter that extends BaseAdapter. It contains more items than what it can fit in the screen.
So I'm using Gallery.getFirstVisiblePosition() and Gallery.getLastVisiblePosition() to get the first and last visible position. But these functions doesn't always return the correct values especially after setting the selected position by calling mGallery.setSelection() followed by a SimpleAdapter.notifyDataChanged() call. Most of the time it getFirstVisiblePosition() returns 0 even if the first element is not visible.
Also note that the no. of visible items in Gallery is different in portrait and landscape mode. The value returned by getFirstVisiblePosition() look correct in landscape but is returned wrong in portrait mode.
Anyone has any thoughts/ideas?
Thanks!
The first visible position will be updated only after a layout. You cannot call notifyDatasetChanged() and right away get the first visible position, you must wait for the next layout pass.