8

Title is clear. I'm having this layout:

_________________
|_______________| <- Toolbar    
|___|___|___|___| <- Tablayout
|               |
|               |
|   ViewPager   |
|               |
|_______________|

Both toolbar and tablayout are inside an AppBarLayout, so I can use scroll flags to hide the toolbar on scrolling toward the top. The problem is that this only works with nested-scrolling-supported views. Most of the tabs - I mean, most of the pages - are support.v4.NestedScrollViews, so that is OK; others are (and need to be) ListViews.

From Lollipop on, I can simply add android:nestedScrollingEnabled="true" to the list view, and the toolbar hides correctly on scroll.

On API<21, though, there's no such attribute and the toolbar doesn't hide. Even more important, the very last items in the list are hidden, because of some measuring bug in CoordinatorLayout: listview acts as if it had the space currently occupied by the toolbar.

Solutions:

  • Switch to RecyclerView, which does support nested scrolling: I can't, because I need to use an external-library adapter that works only with adapter views and that I can't replace (namely, ParseQueryAdapter);

  • Extend ListView and implement nested scrolling: seems way to complicated;

  • Extend ListView and implement some workaround, like measuring stuff to avoid the last-item issue or (and) a custom behavior to make the toolbar hide: seems complicated too;

  • Use some layout trick: found none.

Any help?

For example, I (desperately) tried:

<android.support.v4.widget.NestedScrollView
    android:nestedScrollingEnabled="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>

</android.support.v4.widget.NestedScrollView>

But this way the ListView is not laid out as match_parent. I get a little view with small height, and the rest of the page is empty.

natario
  • 24,414
  • 15
  • 86
  • 151

3 Answers3

2

Unfortunately, there is no way to get nested scrolling working on ListView - otherwise it wouldn't require the modifications that were done in API 21.

You'll note that the current Parse SDK has actually removed ParseQueryAdapter entirely. Given that, it may make sense to start building your own RecyclerView based adapter using the Parse query APIs directly.

ianhanniballake
  • 176,061
  • 29
  • 414
  • 404
  • I'm not on the very last release, but I remember that class not being listed in the public APIs for long. Thank you, however, for the "you can't" - I spent some hours dealing with NestedScrolling interfaces. – natario Sep 28 '15 at 08:49
  • "there is no way to get nested scrolling working on ListView". There is ViewCompat.setNestedScrollingEnabled(ListView, boolean); – Dogcat Mar 16 '17 at 05:55
  • 2
    @Dogcat - which does nothing prior to API 21. It just saves you from having to check the API level. – ianhanniballake Mar 16 '17 at 12:57
  • 2
    @Dogcat - the [pre-API 21 source code](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/compat/java/android/support/v4/view/ViewCompat.java#965) requires the view to implement the Support Library's `NestedScrollingChild` interface, which a framework class like `ListView` will never do. It is only on [API 21+](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/compat/api21/android/support/v4/view/ViewCompatLollipop.java#148) that it calls through to the framework `setNestedScrollingEnabled`, which `ListView` does implement. – ianhanniballake Mar 16 '17 at 13:53
1

For those intersted in the specific ParseQueryAdapter issue,

natario
  • 24,414
  • 15
  • 86
  • 151
1

I'm actually a Xamarin developer so I can't test if this works in this particular case, but I found an answer which helped me in Xamarin, so I'm gonna share it:

I found a solution that works excellently and can scroll the ListView without problems:

ListView lv = (ListView)findViewById(R.id.myListView);  // your
listview inside scrollview lv.setOnTouchListener(new
ListView.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            // Disallow ScrollView to intercept touch events.
            v.getParent().requestDisallowInterceptTouchEvent(true);
            break;

        case MotionEvent.ACTION_UP:
            // Allow ScrollView to intercept touch events.
            v.getParent().requestDisallowInterceptTouchEvent(false);
            break;
        }

        // Handle ListView touch events.
        v.onTouchEvent(event);
        return true;
    }
});

What this does is disable the TouchEvents on the ScrollView and make the ListView intercept them. It is simple and works all the time.

If this won't work, please tell me so I can delete this answer. But maybe it helps anyone since I also found this question and it seems to have no solution.

Dennis Schröer
  • 2,322
  • 14
  • 45