定义自己的CoorDinatorLayout(NestedScrollingParent)

先看一张效果图:


先分析一些源码:

CoorDinatorLayout:

public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent


NestedScrollingParent:

    /**
     * 引用此接口的条件:
     * 1.继承ViewGroup或ViewGroup子类
     * 2.子View中包含可以滚动的ChildView(例如:RecyclerView)
     */
    public interface NestedScrollingParent {
        /**
         * 列表滚动时首先调用
         * nestedScrollAxes用来判断滑动方向:SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL, SCROLL_AXIS_NONE
         * @param child
         * @param target
         * @param nestedScrollAxes
         * @return
         */
        public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);

        /**
         * onStartNestedScroll之后调用
         * @param child
         * @param target
         * @param nestedScrollAxes
         */
        public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);

        /**
         * 滚动停止调用
         * @param target
         */
        public void onStopNestedScroll(View target);

        /**
         * 滚动之前调用,一般用此方法来消耗滚动
         * consumed[0]用来消耗x方法, consumed[1]用来消耗y方法.
         * 如果dy或dy未被完全消耗,则传递给剩余部分给滚动View自行处理
         * @param target
         * @param dx
         * @param dy
         * @param consumed
         */
        public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);

        /**
         *滚动中
         * @param target
         * @param dxConsumed
         * @param dyConsumed
         * @param dxUnconsumed
         * @param dyUnconsumed
         */
        public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed);


        /**
         * 快速滑动前调用
         * @param target
         * @param velocityX
         * @param velocityY
         * @return
         */
        public boolean onNestedPreFling(View target, float velocityX, float velocityY);

        /**
         * onNestedPreFling之后调用
         * @param target
         * @param velocityX
         * @param velocityY
         * @param consumed
         * @return
         */
        public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);

        /**
         * 获取当前滚动方向
         * @return
         */
        public int getNestedScrollAxes();
    }


测试:

缓慢滑动:

08-23 10:57:13.479 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onStartNestedScroll: 
08-23 10:57:13.479 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedScrollAccepted: 
08-23 10:57:13.596 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.614 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.631 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.646 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.662 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.678 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.695 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.712 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.728 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.744 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.760 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.777 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.794 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.810 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.827 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.843 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.861 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.877 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.893 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:13.921 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreFling: 
08-23 10:57:13.921 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedFling: 
08-23 10:57:13.923 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onStopNestedScroll: 

快速滑动:

08-23 10:57:56.599 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onStartNestedScroll: 
08-23 10:57:56.599 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedScrollAccepted: 
08-23 10:57:56.690 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:56.708 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:56.723 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:56.740 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:56.743 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedScroll: 
08-23 10:57:56.757 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:56.758 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedScroll: 
08-23 10:57:56.774 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreScroll: 
08-23 10:57:56.776 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedScroll: 
08-23 10:57:56.776 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedPreFling: 
08-23 10:57:56.776 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onNestedFling: 
08-23 10:57:56.778 22139-22139/com.test.git.coordinatorlayout I/ViewParent: onStopNestedScroll: 


下面上Demo源码:

ViewParent:

package com.test.git.coordinatorlayout.Behavior;

import android.content.Context;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.OverScroller;

/**
 * Created by lk on 16/8/22.
 */
public class ViewParent extends FrameLayout implements NestedScrollingParent {
    private final OverScroller mScroller;
    private int mHeaderHeight;
    private View viewHeader;
    private RecyclerView mRecyclerView;
    private static final String TAG = "ViewParent";

    public ViewParent(Context context) {
        this(context, null);
    }

    public ViewParent(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = new OverScroller(context);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        for(int i = 0; i < getChildCount(); i ++) {
            if(i == 0) {
                viewHeader = getChildAt(0);
            }else {
                View vchild = getChildAt(i);
                if(vchild instanceof RecyclerView){
                    mRecyclerView = (RecyclerView)vchild;
                }
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //测量分割栏的高度
        getChildAt(1).measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        ViewGroup.LayoutParams params = mRecyclerView.getLayoutParams();
        //设置滚动列表高度
        params.height = getMeasuredHeight() - getChildAt(1).getMeasuredHeight();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //获取头部高度
        mHeaderHeight = viewHeader.getMeasuredHeight();
    }

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        Log.i(TAG, "onStartNestedScroll: ");
        //判断是否纵向滑动
        return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
        Log.i(TAG, "onNestedScrollAccepted: ");
    }

    @Override
    public void onStopNestedScroll(View target) {
        Log.i(TAG, "onStopNestedScroll: ");
    }

    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        Log.i(TAG, "onNestedScroll: ");
    }

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        Log.i(TAG, "onNestedPreScroll: ");
        //dy > 0 向上滑动  getScrollY() < mHeaderHeight 头部未完全隐藏
        boolean hide = dy > 0 && getScrollY() < mHeaderHeight;
        //dy < 0 向下滑动  getScrollY() >= 0 头部未完全显示
        //ViewCompat.canScrollVertically(target, -1)  -1 表示scrolling up, 如果target可以向上滑动返回true, 否则返回false.
        boolean show = dy < 0 && getScrollY() >= 0 && !ViewCompat.canScrollVertically(target, -1);

        if (show) {//显示
            if(getScrollY() + dy < 0){
                int sy = - getScrollY();
                scrollBy(0, sy);
                consumed[1] = sy;
            }else {
                scrollBy(0, dy);
                consumed[1] = dy;
            }
        }


        if(hide){//隐藏
            if(dy + getScrollY() > mHeaderHeight){
                int sy = mHeaderHeight - getScrollY();
                scrollBy(0, sy);
                consumed[1] = sy;
            }else {
                scrollBy(0, dy);
                consumed[1] = dy;
            }
        }
    }

    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        Log.i(TAG, "onNestedFling: ");
        return false;
    }

    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        Log.i(TAG, "onNestedPreFling: ");
        Log.i(TAG, "onNestedFling: ");
        //头部隐藏,则交给滚动列表处理
        if(getScrollY() >= mHeaderHeight) {
            return false;
        }
        //滚动
        mScroller.fling(0, getScrollY(), 0, (int) velocityY, 0, 0, 0, mHeaderHeight);
        invalidate();
        return true;
    }

    @Override
    public int getNestedScrollAxes() {
        Log.i(TAG, "getNestedScrollAxes: ");
        return 0;
    }

    float a = 0.5f;//视差因子
    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
        if(y >= 0 && y <= mHeaderHeight){
            viewHeader.scrollTo(0, (int) (- y * a));
        }
    }

    @Override
    public void computeScroll() {
        if(mScroller.computeScrollOffset()){
            scrollTo(0, mScroller.getCurrY());
            invalidate();
        }
    }
}



xml:

<?xml version="1.0" encoding="utf-8"?>
<com.test.git.coordinatorlayout.Behavior.ViewParent xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.MainActivity">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@mipmap/ic_launcher"
            />
    </FrameLayout>
    <Button
        android:id="@+id/bt_click"
        android:textSize="15dp"
        android:text="分割线"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_marginTop="200dp"
        android:layout_gravity="center_horizontal"
        />
    <android.support.v7.widget.RecyclerView
        android:id="@+id/mRecyclerView"
        android:layout_marginTop="250dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
</com.test.git.coordinatorlayout.Behavior.ViewParent>

相关文章: 点击打开链接    点击打开链接

源码:点击打开链接


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值