自定义CoordinatorLayout.Behavior和RecyclerView滚动问题

时间:2016-09-27 12:02:41

标签: android android-recyclerview coordinator-layout

我有CoordinatorLayout有两个孩子,View作为标题和RecyclerView

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center_horizontal"
        app:layout_behavior="some.package.AlphaBehavior">

        <ImageView
            android:id="@+id/header_iv"
            style="@style/some_style"/>

        <TextView
            android:id="@+id/header_retails_tv"
            style="@style/some_style_tv"
            android:text="@string/some_text"/>

        </LinearLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false" />

</android.support.design.widget.CoordinatorLayout>

我使用标题大小动态地将填充设置为RecyclerView,并将clipToPadding设置为false,因此RecyclerView显示在标题下方,当用户向上滚动,标题视图上方显示RecyclerView

我制作了一个自定义CoordinatorLayout.Behavior,以便在用户向上滚动list时完成淡出视图,并在标题必须再次可见时淡入淡出{{1 }}:

AlphaBehavior

但是我遇到了一个问题:如果用户滚动非常快,则行为事件的调用不正确。 public class AlphaBehavior extends CoordinatorLayout.Behavior { private float alpha = 1.0f; private float scrolly = 0.f; private int headerSize = 0; private Animation defaultFadeInAnimation; public AlphaBehavior(Context context, AttributeSet attrs) { super(context, attrs); defaultFadeInAnimation = AnimationUtils.loadAnimation(context, android.R.anim.fade_in); } public void setHeaderSize(int headerSize) { this.headerSize = headerSize; } @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { return dependency instanceof RecyclerView; } @Override public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { scrolly += dyConsumed; Log.d(Constants.TAG, dyConsumed + "/" + dyUnconsumed + "/" + scrolly); float totalScrollY = ((RecyclerView)target).computeVerticalScrollOffset(); Log.d(Constants.TAG, "totalScrollY:" + totalScrollY); alpha = (headerSize - totalScrollY) / headerSize; if (alpha < 0.f) alpha = 0.f; if (alpha > 1.0f) alpha = 1.f; if (dyConsumed < 0 && totalScrollY > headerSize) { alpha = 0.f; } Log.d(Constants.TAG, "alpha:" + alpha); child.setAlpha(alpha); } @Override public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { int pos = ((LinearLayoutManager)((RecyclerView)target).getLayoutManager()).findFirstCompletelyVisibleItemPosition(); Log.d(Constants.TAG, "pos:" + pos); if (pos == 0 && child.getAlpha() == 0.f) { child.startAnimation(defaultFadeInAnimation); } } // overriding this in case we don't the other events are not called @Override public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL; } } 成员与总滚动不完全相关,scrollY成员(从totalScrollY计算滚动获得)不正确。即使我试图在RecyclerView事件中找到firstCompletelyVisibleItem,但当onStopNestedScroll达到列表的开头时,它会返回第2或第3位。

1 个答案:

答案 0 :(得分:4)

最后,我使用OnScrollListener而不是使用CoordinatorLayout.Behavior来解决它,它就像一个魅力。我把代码,也许对某人有用:

自定义onScrollListener以隐藏视图:

public class HideViewOnScrollListener extends RecyclerView.OnScrollListener {

    private float alpha = 1.f;
    private float scrolly = 0.f;

    private int heightViewToHide;
    private final View viewToHide;

    public HideViewOnScrollListener(View viewToHide) {
        this.viewToHide = viewToHide;

        heightViewToHide = viewToHide.getHeight();
        if (heightViewToHide == 0) {

            ViewTreeObserver viewTreeObserver = viewToHide.getViewTreeObserver();
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {

                    heightViewToHide = viewToHide.getHeight();

                    if (heightViewToHide > 0)
                        viewToHide.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            });
        }

    }

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        scrolly += dy;

        alpha = (heightViewToHide - scrolly) / heightViewToHide;

        if (alpha < 0.f) alpha = 0.f;
        if (alpha > 1.0f) alpha = 1.f;

        if (dy < 0 && scrolly > heightViewToHide) {
            alpha = 0.f;
        }

        viewToHide.setAlpha(alpha);
    }
}

您可以这样添加到RecyclerView:

recyclerView.addOnScrollListener(new HideViewOnScrollListener(viewToHide));