marmor
marmor

Reputation: 28179

ScrollingViewBehavior for ListView

I have two activities using AppBarLayout with a Toolbar and TabLayout from support library 22.

The layout of both is pretty similar: A Toolbar at the top, below it TabLayout, below it a ViewPager containing 3 Fragments.

The first activity's Fragment has a RecyclerView, the second activity's Fragment is using a ListView instead.

The scrollable Toolbar example from https://github.com/chrisbanes/cheesesquare is working fine on the first activity using the RecyclerView, but on with the ListView.

I've tried created a custom ListViewScrollBehavior that extends AppBarLayout.ScrollingViewBehavior, but so far no luck. The TouchEvents are passed to the custom class only for horizontal scrolling, but not when scrolling the ListView (vertically).

Any way to use a CoordinatorLayout with ListView?

Upvotes: 34

Views: 19226

Answers (6)

A P
A P

Reputation: 2548

You can add

    android:nestedScrollingEnabled="true"

to the ListView from XML, just note that this only supports API 21+. Alternatively, you can swap out your ListView for a RecyclerView, and that should work better.

Upvotes: 0

Ahamadullah Saikat
Ahamadullah Saikat

Reputation: 4644

ListView ScrollingViewBehavior supports only >= 21.

Otherwise you should to write code as below way:

private int mPreviousVisibleItem;


if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    listView.setNestedScrollingEnabled(true);
} else {
    listView.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
        }
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (firstVisibleItem > mPreviousVisibleItem) {
                appBarLayout.setExpanded(false, true);
            } else if (firstVisibleItem < mPreviousVisibleItem) {
                appBarLayout.setExpanded(true, true);
            }
            mPreviousVisibleItem = firstVisibleItem;
        }
    });
}

Upvotes: 1

I Love Coding
I Love Coding

Reputation: 331

To a view able to react on AppBarLayout, it need to implement NestedScrollingChild. ListView is not. But it could be implement by a delegate class easily. Use it, it will do like what RecyclerView did

public class NestedScrollingListView extends ListView implements NestedScrollingChild {
private NestedScrollingChildHelper mNestedScrollingChildHelper;

public NestedScrollingListView(final Context context) {
    super(context);
    initHelper();
}

public NestedScrollingListView(final Context context, final AttributeSet attrs) {
    super(context, attrs);
    initHelper();
}

public NestedScrollingListView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initHelper();
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NestedScrollingListView(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    initHelper();
}

private void initHelper() {
    mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
    setNestedScrollingEnabled(true);
}

@Override
public void setNestedScrollingEnabled(final boolean enabled) {
    mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
}

@Override
public boolean isNestedScrollingEnabled() {
    return mNestedScrollingChildHelper.isNestedScrollingEnabled();
}

@Override
public boolean startNestedScroll(final int axes) {
    return mNestedScrollingChildHelper.startNestedScroll(axes);
}

@Override
public void stopNestedScroll() {
    mNestedScrollingChildHelper.stopNestedScroll();
}

@Override
public boolean hasNestedScrollingParent() {
    return mNestedScrollingChildHelper.hasNestedScrollingParent();
}

@Override
public boolean dispatchNestedScroll(final int dxConsumed, final int dyConsumed, final int dxUnconsumed, final int dyUnconsumed, final int[] offsetInWindow) {
    return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}

@Override
public boolean dispatchNestedPreScroll(final int dx, final int dy, final int[] consumed, final int[] offsetInWindow) {
    return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}

@Override
public boolean dispatchNestedFling(final float velocityX, final float velocityY, final boolean consumed) {
    return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}

@Override
public boolean dispatchNestedPreFling(final float velocityX, final float velocityY) {
    return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}

}

Upvotes: 6

hidro
hidro

Reputation: 12521

Alternative solution to Nicolas POMEPUY's answer is to use ViewCompat.setNestedScrollingEnabled(View, boolean)

ViewCompat.setNestedScrollingEnabled(listView, true);

Of course nested scrolling behavior will only work from Lollipop.

Upvotes: 14

Nicolas POMEPUY
Nicolas POMEPUY

Reputation: 1133

The only solution to make it work now is to use this:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
     listView.setNestedScrollingEnabled(true);
}

It will obviously only work on Lollipop.

Upvotes: 38

Theo Kallioras
Theo Kallioras

Reputation: 3677

I believe that the CoordinatorLayout works only with RecyclerView and NestedScrollView. Try wrapping your ListView in a NestedScrollView or convert it to a RecyclerView with a LinearLayoutManager

Upvotes: 11

Related Questions