美文网首页
NestedScrolling

NestedScrolling

作者: 琳子baby | 来源:发表于2018-06-12 14:19 被阅读34次
    11.png
    22.png
    44.png

    一、效果描述

    此控件由两部分组成:顶部布局 + list

    向上滑动,顶部布局未隐藏,整体向上滑动外部view;顶部布局隐藏,滑动内部list

    向下滑动,顶部布局未隐藏,整体向下滑动外部view;顶部布局隐藏,滑动内部list

    二、控件实现

    布局:

    <?xml version="1.0" encoding="utf-8"?>
    <com.example.didi.nestedscrollingdemo.view.NestedScrollingParentView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black">
    
        <TextView
            android:id="@+id/top"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@color/colorAccent"
            android:gravity="center"
            android:textColor="@color/colorPrimaryDark"
            android:text="@string/app_name"/>
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorPrimaryDark">
        </android.support.v7.widget.RecyclerView>
    
    </com.example.didi.nestedscrollingdemo.view.NestedScrollingParentView>
    

    分析:

    主要就是如何实现外部view(即NestedScrollingParentView),NestedScrollingParentView是继承LinearLayout的自定义view,它需要实现NestedScrollingParent,里面有三个方法比较重要,分别是onStartNestedScroll、onNestedPreScroll、onNestedFling

    onStartNestedScroll:是否能接收到内部view滑动时的参数,可直接返回true

    onNestedPreScroll:该方法会传入内部view的移动的dx、dy,可用consumed来控制是否消耗掉dx、dy(即是否不触发内部view滑动事件)

    onNestedFling:可以捕获内部view的fling,返回true则表示拦截内部view事件

    内部view List需要实现NestedScrollingChild(RecyclerView已经实现了NestedScrollingChild)

    核心部分在我们的demo中的具体实现:

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        boolean hiddenTop = dy > 0 && getScrollY() < mTopViewHeight;//若向上滑动,且未隐藏顶部
        boolean showTop = dy < 0 && getScrollY() >= 0 && !ViewCompat.canScrollVertically(target, -1);//若向下滑动,且内部view无法下拉
    
        if (hiddenTop || showTop) {//实现滑动,且消耗掉dy(内部view不滑动)
            scrollBy(0, dy);
            consumed[1] = dy;
        }
    }
    
    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        if (getScrollY() >= mTopViewHeight)//已隐藏顶部
            return false;
    
        fling((int) velocityY);
        return true;
    }
    
    private void fling(int velocityY) {
        mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
        invalidate();
    }
    

    另需实现的方法如下:

    @Override
    public void scrollTo(int x, int y) {  //滚动到的位置
        if (y < 0) {
            y = 0;
        }
        if (y > mTopViewHeight) {
            y = mTopViewHeight;
        }
        if (y != getScrollY()) {
            super.scrollTo(x, y);
        }
    }
    
    @Override
    protected void onFinishInflate()  //加载完layout会回调自定义view的这个方法,可用于获取布局中的控件
    {
        super.onFinishInflate();
        mTop = findViewById(R.id.top);
        mRecycler = findViewById(R.id.recycler_view);
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  //设置view的大小
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ViewGroup.LayoutParams params = mRecycler.getLayoutParams();  //获取到RecyclerView之后,设置其高度,否则向上滑动,由于高度不够,RecyclerView也会跟着向上滑动
        params.height = getMeasuredHeight();
    }
    
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int old)
    
    //布局过程中,会先调用onMeasure设置其大小,再调用onLayout设置位置;布局发送变化时调用此方法,间接调用onMeasure、onLayout
    
    {
        super.onSizeChanged(w, h, oldw, oldh);
        mTopViewHeight = mTop.getMeasuredHeight();  //获得顶部布局的高度
    }
    
    @Override
    public void computeScroll()  //这个方法不是让viewgroup滑动的,真正让viewgroup滑动的是scrollto、scroll by,它由draw来调用
    {
        if (mScroller.computeScrollOffset())//true:尚未滚动结束
        {
            scrollTo(0, mScroller.getCurrY());//完成实际滚动
            invalidate();
        }
    }
    

    相关文章

      网友评论

          本文标题:NestedScrolling

          本文链接:https://www.haomeiwen.com/subject/pjgleftx.html