Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep ScrollView scroll position for dynamic content

What I want to archive can be best explained with an image

enter image description here

The gray box represents the screen, the blue box is meta information, the white rounded box is a SearchView and the red boxes are items returned from the search.

I got this working so far, but the problem occurs when the user searches for something and the items exceed the screen (1). Afterwards the user scrolls down, so the meta information is outside the screen (2). The user can now still enter a new search query and thus change the items. However, when the new query returns too few items to fill the rest of the screen (3) the ScrollView will "jump" back to the top (not in image, not desired). What I want is a behavior where the SearchView stays put (3). Once in this state the user can scroll back to the top (4). If she does she cannot scroll back though, instead the overscroll indicators will show.

Similar behavior can be seen in the Google+ App. From the start screen go to your profile (tap on your name on the top). You will see three registers ("About me", "Posts", "Photos" *). I have for example no photos in there and the behavior is as described.

edit The ScrollView is the root of the View.

edit Basic layout structure

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="fill_parent"
  android:overScrollMode="always"
  android:fillViewport="true">

  <LinearLayout
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_height="wrap_content">
      <View /> <!-- Meta info -->
      <SearchView />
      <View /> <!-- Item representing search result -->
      <View /> <!-- Item representing search result -->
      <View /> <!-- Item representing search result -->
      <View /> <!-- Item representing search result -->
      <View /> <!-- Item representing search result -->
  </LinearLayout>
</ScrollView>

*) Assumed translation from the German App.

like image 998
Mene Avatar asked Jul 14 '14 17:07

Mene


1 Answers

Since there seems to be no standard solution in the android sdk, nor any public code doing this I tinkered my own solution. This is my working solution:

I wrapped the search results in a LinearLayout and used minimumHeight to archive the desired behavior. This way I don't need to fiddle with measurements when items are added to the list.

<LinearLayout
  android:id="@+id/scroll_placeholder"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  >
  <View /> <!-- result -->
  <View /> <!-- result -->
  <View /> <!-- result -->
</LinearLayout>

Search results are retrieved asynchronous so I clear the List and start a search indicator when a new search is triggered. At this point I also set the minimum height to the size of the visible rect of the itemList. Note that the itemList is not a ScrollView as otherwise there would be a ScrollView within a ScrollView which is problematic. It's basically a LinearLayout containing the results.

int scrollY = rootScrollView.getScrollY();
if (scrollY > 0) {
    final Rect visibleListViewRect = new Rect();
    placeholder.getGlobalVisibleRect(visibleListViewRect);
    placeholder.setMinimumHeight(visibleListViewRect.height());
} else {
    placeholder.setMinimumHeight(0);
}

This will give the behavior as seen in image 3) of the question.

To disable scrolling back down once the user has scrolled up (image 4) I added a ScrollChangedListener:

placeholder.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
    @Override
    public void onScrollChanged() {
        int scrollY = placeholder.getScrollY();
        if (scrollY > 0) {
            final Rect visibleListViewRect = new Rect();
            placeholder.getGlobalVisibleRect(visibleListViewRect);
            placeholder.setMinimumHeight(visibleListViewRect.height());
        } else {
            placeholder.setMinimumHeight(0);
        }
    }
});

And that's it.

like image 191
Mene Avatar answered Oct 06 '22 23:10

Mene