安卓滑动控件里嵌套Recyclerview,带浮动效果

最近项目里有这种需求,滑动控件里嵌套Recyclerview,最后项目上线的运行效果:

安卓滑动控件里嵌套Recyclerview,带浮动效果


关键代码已经抽离成一个库:

dependencies {
    //your dependencies ...
    compile 'com.linklink.views:ScrollviewWithinRecyclerviewAndFloatView:1.0.2'
}

demo效果:

安卓滑动控件里嵌套Recyclerview,带浮动效果


界面结构:

整个界面是Fragment,里面填充子Fragment:

安卓滑动控件里嵌套Recyclerview,带浮动效果


使用示例:

1,添加依赖:

dependencies {
    // your dependencies ...
    compile 'com.linklink.views:ScrollviewWithinRecyclerviewAndFloatView:1.0.2'
}

2,MainActivity.java:

package linklink.com.demo;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Fragment fragment=new MyFragment();
        if(fragment!=null){
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commitAllowingStateLoss();
        }
    }
}

3,MyFragment.java,实现CustomMainFragment里的抽象方法:

package linklink.com.demo;

import android.view.LayoutInflater;
import android.view.View;

import java.util.ArrayList;

import linklink.com.scrollview_within_recyclerview.base.CustomBaseFragment2;
import linklink.com.scrollview_within_recyclerview.ui.*;
import linklink.com.scrollview_within_recyclerview.utils.DensityUtil;

/**
 * MyFragment
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2018/6/25  16:43
 * Copyright : 2017-2018 深圳令令科技有限公司-版权所有
 **/
public class MyFragment extends CustomMainFragment {

    @Override
    public int getTitleBackgroundRes(){
        //设置透明控件的背景资源.
        return R.drawable.shape_blue_rect;
    }

    @Override
    public View getTitleView(){
        //设置顶部的title布局
        return LayoutInflater.from(getActivity()).inflate(R.layout.title, null);
    }

    @Override
    public int getTitleViewParentHeight(){
        //设置getTitleView()的父容器的高度值.返回title的实际高度 加上 getTitleViewMarginTop()就行
        return DensityUtil.dp2px(getActivity(),50)  +  getTitleViewMarginTop();//50是title布局里写死的50dp
    }


    @Override
    public int getTitleViewMarginTop() {
        //设置TitleView的MarginTop,单位:像素.因为有些界面可能包含了顶部的状态栏.
        // 包含了状态栏,这个方法返回你获取的状态栏高度
        // 不包含状态栏,这个方法直接返回0
        return DensityUtil.dp2px(getActivity(),20);
    }

    @Override
    public View getHeadView(){
        //这里可以返回一个左右滑动的banner.滑动事件的分发逻辑已经处理过
        return LayoutInflater.from(getActivity()).inflate(R.layout.banner, null);
    }

    @Override
    public View getFloatView(){
        //设置悬浮控件,如果需要与viewpager绑定,可以定义一个成员变量,然后重写onActivityCreated,添加绑定逻辑
        return LayoutInflater.from(getActivity()).inflate(R.layout.float_view, null);
    }

    @Override
    public ArrayList<CustomBaseFragment2> getSubFragments(){
        //在viewpager里添加子碎片.CustomBaseFragment2
        ArrayList<CustomBaseFragment2> list =new ArrayList<>();
        SubFragment1 subFragment1=new SubFragment1();
        list.add(subFragment1);

        SubFragment2 subFragment2=new SubFragment2();
        list.add(subFragment2);
        return list;
    }
}

3,SubFragment.java,实现CustomBaseFragment2的方法:

package linklink.com.demo;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

import linklink.com.scrollview_within_recyclerview.R;
import linklink.com.scrollview_within_recyclerview.base.CustomBaseFragment2;
import linklink.com.scrollview_within_recyclerview.utils.LogUtil;

/**
 * SubFragment1
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2018/6/25  14:39
 * Copyright : 2017-2018 深圳令令科技有限公司-版权所有
 **/
public class SubFragment1 extends CustomBaseFragment2 {


    private static  String TAG = "SubFragment1";

    protected RecyclerView mRecyclerView;//可以改为自己的带刷新的控件.也可以是Listview


    private ArrayList<String> mDatas;

    //滑到顶部,       这个方法在控件还原初始状态时会调用,可以不重写
    public void setSelection(int position){
        try {
            if(position==0){
                mRecyclerView.smoothScrollToPosition(position);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //第一个item(包含headview)是否在顶部
    public boolean isHeadviewAtTopNow(){
        LogUtil.i(TAG,"mRecyclerView:"+mRecyclerView);

        View view = mRecyclerView.getChildAt(0);

        LogUtil.i(TAG,"view:"+view);

        if(mRecyclerView!=null&&view!=null){

            int[] outLocation=new int[2];
            view.getLocationOnScreen(outLocation);

            int[] outLocation2=new int[2];
            mRecyclerView.getLocationOnScreen(outLocation2);

            LogUtil.i(TAG,"第一个view在屏幕上的绝对位置,outLocation[1]:"+outLocation[1]);
            LogUtil.i(TAG,"recyclerview在屏幕上的绝对位置,outLocation2[1]:"+outLocation2[1]);


            //return mRecyclerViewHeadView.getTop()==0;
            return outLocation[1]==outLocation2[1];
        }
        else{
            LogUtil.i(TAG,"mRecyclerViewHeadView==null,return false");
            return false;
        }

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        TAG=this.getClass().getSimpleName();
        return inflater.inflate(R.layout.fragment_sub, container, false);
    }


    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        initData();

        mRecyclerView = (RecyclerView) getView().findViewById(R.id.id_recyclerview);
        //设置布局管理器
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        //设置adapter
        HomeAdapter adapter = new HomeAdapter();
        mRecyclerView.setAdapter(adapter);
        //设置Item增加、移除动画
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        //添加分割线
        mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.HORIZONTAL));
    }

    private class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
    {
        //生成holder
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    getActivity()).inflate(R.layout.item, parent,
                    false));
            return holder;
        }

        //绑定holder
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position)
        {
            holder.tv.setText(mDatas.get(position));
        }

        @Override
        public int getItemCount()
        {
            return mDatas.size();
        }

        class MyViewHolder extends RecyclerView.ViewHolder
        {

            TextView tv;

            public MyViewHolder(View view)
            {
                super(view);
                tv = (TextView) view.findViewById(R.id.id_num);
            }
        }
    }

    protected void initData()
    {
        mDatas = new ArrayList<String>();
        for (int i = 'A'; i <= 'z'; i++)
        {
            mDatas.add(getFragmentMark() + (char) i);
        }
    }


    //为了界面上区分子页,加个前缀
    protected String getFragmentMark(){
        return  "碎片1_ ";
    }
}

实现方式:

1,顶部的事件分发控件MyDispatchRelativeLayout2,重写了onInterceptTouchEvent,上下滑动,则拦截,自己处理掉事件:

package linklink.com.scrollview_within_recyclerview.custom_view;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

import linklink.com.scrollview_within_recyclerview.utils.LogUtil;


/**
 * MyDispatchRelativeLayout2
 * 重写事件拦截
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2018/5/23  16:45
 * Copyright : 2014-2017 深圳令令科技有限公司-版权所有
 **/

public class MyDispatchRelativeLayout2 extends RelativeLayout {


    private static  final String TAG="MyDispatchLinearLayout";
    private static final int SCROLL_THRESHOLD = 50;


    public MyDispatchRelativeLayout2(Context context) {
        super(context);
    }


    public MyDispatchRelativeLayout2(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyDispatchRelativeLayout2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    private int mActionDownY,mLastY,mLastRawY;

    //上下滑动,则拦截,自己处理掉事件
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        //return super.onInterceptTouchEvent(ev);

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN://按下时记录纵坐标

                mLastY = (int) event.getY();//最后一个action时Y值
                LogUtil.e(TAG, "mLastY:" + mLastY);

                mActionDownY = (int) event.getY();//按下的瞬间Y
                LogUtil.e(TAG, "mActionDownY:" + mActionDownY);

                mLastRawY= (int) event.getRawY();//记录y值返回给其子控件使用

                LogUtil.e(TAG, "=============================ACTION_DOWN,mLastY" + mLastY);

                if(mActionDownCallBack!=null){
                    mActionDownCallBack.recordActionDownY(mLastRawY);
                }

                break;

            case MotionEvent.ACTION_MOVE:

                LogUtil.e(TAG, "=============================ACTION_MOVE");
                LogUtil.e(TAG, "event.getY()=============================" + event.getY());

                int dY = (int) event.getY() - mActionDownY;
                LogUtil.e(TAG, "dY=============================" + dY);


                if(Math.abs(dY)>=SCROLL_THRESHOLD){//是上下滑动,则拦截,此view自己来处理事件
                    return true;
                }
                break;

            case MotionEvent.ACTION_UP://注意,全部是getRawX和getRawY
                LogUtil.e(TAG, "MotionEvent.ACTION_UP");
                break;


            case MotionEvent.ACTION_CANCEL:
                break;

        }

        return false;

    }

    public ActionDownCallBack getmActionDownCallBack() {
        return mActionDownCallBack;
    }

    public void setmActionDownCallBack(ActionDownCallBack mActionDownCallBack) {
        this.mActionDownCallBack = mActionDownCallBack;
    }

    private ActionDownCallBack mActionDownCallBack;//按下一瞬间的rawY的处理

    public interface ActionDownCallBack {
        void recordActionDownY(int mLastRawY);
    }

}

2,ViewPager的父容器也是一个自定义控件MyDispatchRelativeLayout,也重写了onInterceptTouchEvent,与上面不同的是,是否拦截,通过一个接口来实现:

package linklink.com.scrollview_within_recyclerview.custom_view;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

import linklink.com.scrollview_within_recyclerview.utils.LogUtil;


/**
 * MyDispatchRelativeLayout
 * 重写事件拦截
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2018/5/23  16:45
 * Copyright : 2014-2017 深圳令令科技有限公司-版权所有
 **/

public class MyDispatchRelativeLayout extends RelativeLayout {


    private static  final String TAG="MyDispatchRelativeLayout";
    public static final int SCROLL_THRESHOLD = 10;//横向滑动超过两个像素,就算是横向滑动


    public MyDispatchRelativeLayout(Context context) {
        super(context);
    }


    public MyDispatchRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyDispatchRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    private float mActionDownX, mLastX;
    private float mActionDownY, mLastY;
    private int mActionDownRowY;



    /**
     * @method name:onInterceptTouchEvent
     * @des:左右滑动不拦截   上下滑动,根据接口的返回值来决定是否拦截
     * @param :[event]
     * @return type:boolean
     * @date 创建时间:2018/5/23
     * @author Chuck
     **/
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        if(1==0){//测试,全部拦截.自己处理事件,如果需要分发,则手动分发
            return true;
        }

        //return super.onInterceptTouchEvent(ev);

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN://按下时记录纵坐标



                LogUtil.i(TAG, "=============================ACTION_DOWN,getX()=" + event.getX());
                LogUtil.i(TAG, "=============================ACTION_DOWN,getY()=" + event.getY());
                LogUtil.i(TAG, "=============================ACTION_DOWN,getRowX()=" + event.getRawX());
                LogUtil.i(TAG, "=============================ACTION_DOWN,getRowY()=" + event.getRawY());

                mLastX =  event.getX();//最后一个action时X值
                //LogUtil.i(TAG, "=============================ACTION_DOWN,mLastX" + mLastX);


                mActionDownX =  event.getX();//按下的瞬间Y
                //LogUtil.i(TAG, "mActionDownX:" + mActionDownX);


                mLastY =  event.getY();//最后一个action时Y值
                //LogUtil.i(TAG, "mLastY:" + mLastY);

                mActionDownY =  event.getY();//按下的瞬间Y
                //LogUtil.i(TAG, "mActionDownY:" + mActionDownY);



                mActionDownRowY = (int) event.getRawY();//按下的瞬间mActionDownRowY
                //LogUtil.i(TAG, "mActionDownRowY:" +mActionDownRowY);

                //LogUtil.i(TAG, "=============================ACTION_DOWN,mLastY" + mLastY);

                if(mInterceptProvider!=null){
                    mInterceptProvider.onActionDown(mActionDownRowY);
                }
                break;

            case MotionEvent.ACTION_MOVE://左右滑动,不拦截.上下滑动,由接口来决定是否拦截 by:Chuck 2018/05/23

                LogUtil.i(TAG, "=============================ACTION_MOVE,getX()=" + event.getX());
                LogUtil.i(TAG, "=============================ACTION_MOVE,getY()=" + event.getY());
                LogUtil.i(TAG, "=============================ACTION_MOVE,getRowX()=" + event.getRawX());
                LogUtil.i(TAG, "=============================ACTION_MOVE,getRowY()=" + event.getRawY());



                float dX =  event.getX() - mActionDownX;


                LogUtil.i(TAG, "dX=============================" + dX);

                float dY =  event.getY() - mActionDownY;
                LogUtil.i(TAG, "dY=============================" + dY);

                LogUtil.i(TAG, "Math.abs(dX)=============================" + Math.abs(dX));
                LogUtil.i(TAG, "Math.abs(dY)=============================" + Math.abs(dY));

                if(Math.abs(dX)==0&& Math.abs(dY)==0){//实测的时候,发现有这种情况出现:手指上滑,但是坐标没变
                    LogUtil.i(TAG, "Math.abs(dX)==0&&Math.abs(dY)==0,不拦截" );

                    return false;//不拦截
                }
                else if(Math.abs(dX)> Math.abs(dY)){//横向滑动的距离大于纵向的,则不拦截
                    LogUtil.i(TAG, "Math.abs(dX)>Math.abs(dY),不拦截" );

                    return false;//不拦截
                }
                else{//横向滑动的距离小于纵向

                    if(Math.abs(dX)>SCROLL_THRESHOLD){//左右滑动的距离超过了阈值,则不拦截,子控件处理

                        LogUtil.i(TAG, "不拦截:Math.abs(dX)" + Math.abs(dX));

                        return false;
                    }
                    else{//判定为 上下滑动事件
                        if(mInterceptProvider!=null){//接口来处理是否拦截. "醉美大连"业务里的是切换的tab已经浮动到了顶部,则里面的viewPager里的recyclerView可以滑动

                            //现在记录的是getY,也就是距离view边界的距离,上滑的话,新的y会比旧的y小
                            boolean isScrollUp=event.getY()<=mActionDownY;

                            if(event.getY()==mActionDownY){//y值没变默认为上滑.经实测,下滑不会出问题.但是有时候上滑,y值拿不到
                                isScrollUp=true;
                            }
                            LogUtil.i(TAG, "上滑? :" + isScrollUp);

                            boolean intercept=mInterceptProvider.onInterceptTouchEvent(isScrollUp);
                            LogUtil.i(TAG, "接口的返回值:" + intercept+(intercept?",拦截":",不拦截"));

                            return intercept;
                        }
                    }
                }

                break;

            case MotionEvent.ACTION_UP:
                LogUtil.i(TAG, "MotionEvent.ACTION_UP");
                break;


            case MotionEvent.ACTION_CANCEL:
                break;

        }

        return false;

    }
/*
    */
/**
     * @method name:onInterceptTouchEvent
     * @des:左右滑动不拦截   上下滑动,根据接口的返回值来决定是否拦截
     * @param :[event]
     * @return type:boolean
     * @date 创建时间:2018/5/23
     * @author Chuck
     **//*

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {


        //return super.onInterceptTouchEvent(ev);

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN://按下时记录纵坐标

                mLastX = (int) event.getRawX();//最后一个action时X值
                LogUtil.i(TAG, "mLastX:" + mLastX);

                mActionDownX = (int) event.getRawX();//按下的瞬间Y
                LogUtil.i(TAG, "mActionDownX:" + mActionDownX);

                LogUtil.i(TAG, "=============================ACTION_DOWN,mLastX" + mLastX);

                mLastY = (int) event.getRawY();//最后一个action时Y值
                LogUtil.i(TAG, "mLastY:" + mLastY);

                mActionDownY = (int) event.getRawY();//按下的瞬间Y
                LogUtil.i(TAG, "mActionDownY:" + mActionDownY);

                LogUtil.i(TAG, "=============================ACTION_DOWN,mLastY" + mLastY);

                if(mInterceptProvider!=null){
                    mInterceptProvider.onActionDown(mActionDownY);
                }
                break;

            case MotionEvent.ACTION_MOVE://左右滑动,不拦截.上下滑动,由接口来决定是否拦截 by:Chuck 2018/05/23

                LogUtil.i(TAG, "=============================ACTION_MOVE");
                LogUtil.i(TAG, "event.getRawX()=============================" + event.getRawX());

                int dX = (int) event.getRawX() - mActionDownX;
                LogUtil.i(TAG, "event.getRawX()===================y==========" + event.getRawX());

                LogUtil.i(TAG, "dX===================y==========" + dX);

                int dY = (int) event.getRawY() - mActionDownY;
                LogUtil.i(TAG, "event.getRawY()=============================" + event.getRawY());
                LogUtil.i(TAG, "dY=============================" + dY);

                if(Math.abs(dX)>SCROLL_THRESHOLD){//左右滑动的距离超过了阈值,则不拦截,子控件处理

                    LogUtil.i(TAG, "不拦截:Math.abs(dX)" + Math.abs(dX));

                    return false;
                }
                else{
                    if(mInterceptProvider!=null){//接口来处理是否拦截. "醉美大连"业务里的是切换的tab已经浮动到了顶部,则里面的viewPager里的recyclerView可以滑动

                        boolean isScrollUp=(mActionDownY-event.getRawY())>0;
                        LogUtil.i(TAG, "上滑? :" + isScrollUp);

                        boolean intercept=mInterceptProvider.onInterceptTouchEvent(isScrollUp);
                        LogUtil.i(TAG, "接口的返回值:" + intercept+(intercept?",拦截":",不拦截"));

                        return intercept;
                    }
                }



                break;

            case MotionEvent.ACTION_UP:
                LogUtil.i(TAG, "MotionEvent.ACTION_UP");
                break;


            case MotionEvent.ACTION_CANCEL:
                break;

        }

        return false;

    }
*/

    //实现是否拦截当前的事件
    public interface InterceptProvider{
        boolean onInterceptTouchEvent(boolean isScrollUp);
        void onActionDown(int actionDownY);
    }

    private InterceptProvider mInterceptProvider;

    public InterceptProvider getmInterceptProvider() {
        return mInterceptProvider;
    }

    public void setmInterceptProvider(InterceptProvider mInterceptProvider) {
        this.mInterceptProvider = mInterceptProvider;
    }
    
}

3,核心的事件分发,处理类:CustomMainFragment,它主要做的是:当上下滑动顶部的广告控件或悬浮控件时,通过设置marginTop来制造界面的"滑动"(滑动时,顶部的透明度随之改变);当viewpager"滑动"到顶部时(这个值是广告控件高度减去title总高度),此时再滑动viewpager(它父容器是一个自定义控件,会有事件拦截逻辑)时,会走分支:

A:如果此时viewpager里的recyclerView或者Listview的第一个item(含headview)正在顶部(判断是否正在顶部,是子类fragment必须实现的一个方法),如果是上滑,则不拦截事件,事件会被viewpager里面的控件消费,也就是recyclerView或者Listview消费;反之,如果此时下滑,则拦截事件,则整个界面会"滑动"下来;

B:如果此时viewpager里的recyclerView或者Listview的第一个item(含headview)不在顶部,则不管上滑或下滑,都不拦截,事件会被viewpager里面的控件消费:

package linklink.com.scrollview_within_recyclerview.ui;

import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import java.util.ArrayList;
import java.util.List;

import linklink.com.scrollview_within_recyclerview.R;
import linklink.com.scrollview_within_recyclerview.base.CustomBaseFragment2;
import linklink.com.scrollview_within_recyclerview.custom_view.MyDispatchRelativeLayout;
import linklink.com.scrollview_within_recyclerview.custom_view.MyDispatchRelativeLayout2;
import linklink.com.scrollview_within_recyclerview.utils.DensityUtil;
import linklink.com.scrollview_within_recyclerview.utils.LogUtil;

/**
 * MainFragment
 * 责任人:  Chuck
 * 修改人: Chuck
 * 创建/修改时间: 2018/6/25  10:11
 * Copyright : 2014-2018 深圳令令科技有限公司-版权所有
 **/
public abstract class CustomMainFragment extends Fragment implements ViewPager.OnPageChangeListener {

    private static final String TAG = "MainFragment";

    protected static final int MARGIN_THRESHOLD = 10;//浮动tab的允许误差值
    private static final int FLOAT_THRESHOLD_Y = 150;//悬浮临界容差
    private static final int DOWN_BACK_THRESHOLD = 1;//是否可以下滑,下滑的上限.有则滑到极限松手,回弹

    protected MyDispatchRelativeLayout2 llHead;
    protected LinearLayout adList;
    protected ImageView ivBackground;
    protected MyDispatchRelativeLayout rlVpContainner;
    protected RelativeLayout  rlTitleFilled;
    protected ViewPager vp;
    private RelativeLayout rl_content_root;


    protected List<CustomBaseFragment2> mPagerList = new ArrayList<CustomBaseFragment2>();// 碎片集合
    protected int initIndex = 0;//子页索引
    protected LinearLayout mTitleViewRoot;
    private LinearLayout mTabContainer;


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        llHead= (MyDispatchRelativeLayout2) getView().findViewById(R.id.ll_head);
        adList= (LinearLayout) getView().findViewById(R.id.ad_list);
        ivBackground= (ImageView) getView().findViewById(R.id.iv_background);
        rlVpContainner= (MyDispatchRelativeLayout) getView().findViewById(R.id.rl_vp_containner);
        rlTitleFilled= (RelativeLayout) getView().findViewById(R.id.rl_title);
        vp= (ViewPager) getView().findViewById(R.id.vp);
        rl_content_root= (RelativeLayout) getView().findViewById(R.id.rl_content_root);

        //重置title高度(子类的title可能需要设置不同的高度)
        ViewGroup.LayoutParams pa=rlTitleFilled.getLayoutParams();
        pa.height= getTitleViewParentHeight();
        LogUtil.i(TAG,"重置title父容器的高度值:"+ getTitleViewParentHeight());
        rlTitleFilled.setLayoutParams(pa);

        ivBackground.setImageResource(getTitleBackgroundRes());
        mTitleViewRoot= (LinearLayout) getView().findViewById(R.id.rl_titlt_root);

        View titleView=getTitleView();
        if(titleView!=null){
            mTitleViewRoot.addView(titleView);
        }
        //重置title的margigTop,以适应不同的状态栏高度
        ViewGroup.MarginLayoutParams titlePa= (ViewGroup.MarginLayoutParams) titleView.getLayoutParams();
        titlePa.setMargins(0, getTitleViewMarginTop(),0,0);




        View headView=getHeadView();
        if(headView!=null){
            adList.addView(headView);
        }

        mTabContainer= (LinearLayout) getView().findViewById(R.id.ll_tab_container);
        View floatView=getFloatView();
        if(floatView!=null){
            mTabContainer.addView(floatView);
        }

        getFragmnets();
        initHeadScrollListener();
        initViewPagerContainerScrollListener();
        getScroolMax();
    }

    protected int mHeadActionDownX, mHeadActionDownY, mHeadLastY, mHeadSlidedDistance, mScroolMax;

    /**
     * @param :[]
     * @return type:void
     * @method name:initHeadScrollListener
     * @des:给列表顶部的控件加滑动监听: 上滑时, 改变控件的位置, 并带动底下的viewpage一起滑动
     * 下滑时类似
     * 手指抬起时,如果是下滑的,则做一个回弹效果
     * @date 创建时间:2018/5/23
     * @author Chuck
     **/
    private void initHeadScrollListener() {

        llHead.setmActionDownCallBack(new MyDispatchRelativeLayout2.ActionDownCallBack() {
            @Override
            public void recordActionDownY(int mLastRawY) {

                LogUtil.e(TAG, "顶部滑动控件,记录父容器按下的y的rawY值:" +mLastRawY);

                mHeadLastY = (int) mLastRawY;//最后一个action时Y值
                mHeadActionDownX = (int) mLastRawY;//按下的瞬间X
            }
        });

        llHead.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(final View v, MotionEvent event) {

                switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN://按下时记录纵坐标


                        if (mScroolMax == 0) {//是个正值,head在上滑的上限值
                            //悬浮于顶部,距离值
                            mScroolMax = adList.getHeight()-rlTitleFilled.getHeight();

                            //mScroolMax = mViewBind.llHead.getHeight() - mViewBind.llTabContainer.getHeight()-mViewBind.rlTitleFilled.getHeight();
                            LogUtil.e(TAG, "能上滑的最大距离:" + mScroolMax);
                        }

                        mHeadLastY = (int) event.getRawY();//最后一个action时Y值
                        mHeadActionDownX = (int) event.getRawX();//按下的瞬间X
                        LogUtil.e(TAG, "mActionDownX:" + mHeadActionDownX);

                        mHeadActionDownY = (int) event.getRawY();//按下的瞬间Y
                        LogUtil.e(TAG, "mActionDownY:" + mHeadActionDownY);

                        LogUtil.e(TAG, "=============================ACTION_DOWN,mLastY" + mHeadLastY);
                        break;

                    case MotionEvent.ACTION_MOVE:

                        LogUtil.e(TAG, "=============================ACTION_MOVE");
                        LogUtil.e(TAG, "event.getRawY()=============================" + event.getRawY());

                        int dY = (int) event.getRawY() - mHeadLastY;
                        LogUtil.e(TAG, "dY=============================" + dY);

                        mHeadSlidedDistance = (int) event.getRawY() - mHeadActionDownY;
                        LogUtil.e(TAG, "mSlidedDistance=============================" + mHeadSlidedDistance);

                        final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
                        int left = params.leftMargin;
                        int top = params.topMargin;
                        int right = params.rightMargin;
                        int bottom = params.bottomMargin;

                        final ViewGroup.MarginLayoutParams vpParams = (ViewGroup.MarginLayoutParams) rlVpContainner.getLayoutParams();
                        //int left = vpParams.leftMargin;
                        //int top = vpParams.topMargin;
                        //int right = vpParams.rightMargin;
                        //int bottom =vpParams.bottomMargin;

                        LogUtil.e(TAG, "left:" + left + ",top:" + top + ",right:" + right + ",bottom" + bottom);

                        int topNew = top + dY;
                        int bottomNew = bottom - dY;


                        int stetchDistance = DOWN_BACK_THRESHOLD;//下滑的回弹距离上限


                        //上滑极限是tab的位置,下滑极限是回弹的距离   topNew小于0是上滑  topNew大于0是下滑  by:Chuck 2018/05/23
                        if ((topNew <= 0 && Math.abs(topNew) <= mScroolMax) || (topNew > 0 && topNew < stetchDistance)) {

                            if(topNew <= 0 && Math.abs(topNew) >= mScroolMax){//滑动超标了.因为回调并不是一个像素一个像素的
                                topNew=-1 * mScroolMax;//赋值为阈值
                            }

                            LogUtil.e(TAG, topNew + "=============================MOVE");
                            params.setMargins(left, topNew, right, bottomNew);
                            v.setLayoutParams(params);

                            vpParams.setMargins(left, topNew, right, bottomNew);
                            rlVpContainner.setLayoutParams(vpParams);
                            mHeadLastY = (int) event.getRawY();

                            //重置顶部title的透明度
                            resetTitleAlpha(bottomNew);
                        }



                        break;

                    case MotionEvent.ACTION_UP://注意,全部是getRawX和getRawY
                        LogUtil.e(TAG, "MotionEvent.ACTION_UP");


                        final ViewGroup.MarginLayoutParams paramsNew = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
                        int topUp = paramsNew.topMargin;

                        final ViewGroup.MarginLayoutParams paramsNew2 = (ViewGroup.MarginLayoutParams) rlVpContainner.getLayoutParams();

                        LogUtil.e(TAG, "MotionEvent.ACTION_UP,topUp" + topUp);

                        if(topUp<=0){//上滑,几乎快要悬浮,则抬手时让它悬浮
                            if(Math.abs(Math.abs(topUp)-mScroolMax)<=FLOAT_THRESHOLD_Y ){
                                paramsNew.setMargins(0, -1 * mScroolMax, 0,mScroolMax);
                                v.setLayoutParams(paramsNew);

                                paramsNew2.setMargins(0,  -1 *mScroolMax, 0,mScroolMax);
                                rlVpContainner.setLayoutParams(paramsNew2);

                                //重置顶部title的透明度
                                resetTitleAlpha(mScroolMax);
                            }

                        }

                        if (topUp > 0) {//topUp>0表示是下滑后抬起手指,此时回弹head和底下的viewPager


                            ValueAnimator anim = ValueAnimator.ofInt(topUp, 0);
                            anim.setDuration(400); // 设置动画运行的时长 anim.setStartDelay(500); // 设置动画延迟播放时间
                            anim.setRepeatCount(0); // 设置动画重复播放次数 = 重放次数+1 // 动画播放次数 = infinite时,动画无限重复
                            // anim.setRepeatMode(ValueAnimator.RESTART);
                            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

                                @Override
                                public void onAnimationUpdate(ValueAnimator animation) {
                                    int currentValue = (Integer) animation.getAnimatedValue();

                                    paramsNew.setMargins(0, currentValue, 0, -1 * currentValue);
                                    v.setLayoutParams(paramsNew);

                                    paramsNew2.setMargins(0, currentValue, 0, -1 * currentValue);
                                    rlVpContainner.setLayoutParams(paramsNew2);
                                }
                            });

                            anim.start();

                            //重置顶部title的透明度
                            resetTitleAlpha(0);

                        }



                        break;


                    case MotionEvent.ACTION_CANCEL:
                        break;

                }
                return true;
            }
        });

    }

    private int mContainerActionDownX, mContainerActionDownY, mContainerLastY, mContainerSlidedDistance;

    /**
     * @param :[]
     * @return type:void
     * @method name:initViewPagerContainerScrollListener
     * @des:给底下的viewpager的父容器控件加滑动监听: 上滑时, 改变控件的位置, 并带动上面的head一起滑动
     * 下滑时类似
     * 手指抬起时,如果是下滑的,则做一个回弹效果
     * 所有的滑动动作使用重置margin来实现
     * @date 创建时间:2018/5/23
     * @author Chuck
     **/
    private void initViewPagerContainerScrollListener() {

        /************
         *
         *  此监听器在控件的纯左右滑动时不会起作用,只在上下滑动时起作用. "醉美大连"业务里:
         tab已经浮动到了顶部,上滑则recyclerView消费滑动事件
         下滑:如果此时headview正在顶部,getY为0,则父容器消费滑动事件
         否recyclerView消费滑动事件(headview看不到了,下滑应该先把headview滑出来)

         tab不在顶部:
         上滑:父容器消费
         下滑:如果tab在原始位置,也就是最低位置,则recyclerView消费滑动事件
         否则:父容器消费滑动事件
         by:Chuck
         *
         *
         */

        rlVpContainner.setmInterceptProvider(new MyDispatchRelativeLayout.InterceptProvider() {

            @Override
            public void onActionDown(int actionDownY) {

                mContainerLastY=actionDownY;
                LogUtil.e(TAG, "通过InterceptProvider接口记录首次按下的Y坐标:" + mContainerLastY);
            }

            @Override
            public boolean onInterceptTouchEvent(boolean isScrollUp) {

                return judgeIntercept(isScrollUp);

            }
        });


        rlVpContainner.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(final View v, MotionEvent event) {

                switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN://按下时记录纵坐标,注意,如果按下时没有记录的话,这个值会是空,所以,在父容器里要把
                        //按下一瞬间的值传过来(接口形式),否则首次的值会是0.结果造成滑动距离超标
                        if (mScroolMax == 0) {//是个正值,head在上滑的上限值
                            //悬浮于顶部,距离值
                            mScroolMax = adList.getHeight()-rlTitleFilled.getHeight();

                            // mScroolMax = mViewBind.llHead.getHeight() - mViewBind.llTabContainer.getHeight();
                            LogUtil.e(TAG, "能上滑的最大距离:" + mScroolMax);
                        }

                        mContainerLastY = (int) event.getRawY();//最后一个action时Y值
                        mContainerActionDownX = (int) event.getRawX();//按下的瞬间X
                        LogUtil.e(TAG, "mContainerActionDownX:" + mContainerActionDownX);

                        mContainerActionDownY = (int) event.getRawY();//按下的瞬间Y
                        LogUtil.e(TAG, "mContainerActionDownY:" + mContainerActionDownY);

                        LogUtil.e(TAG, "=============================ACTION_DOWN,mContainerLastY" + mContainerLastY);

                        return true;//down事件必须消费

                    case MotionEvent.ACTION_MOVE:

                        LogUtil.e(TAG, "=============================ACTION_MOVE");
                        LogUtil.e(TAG, "event.getRawX()=============================" + event.getRawX());
                        LogUtil.e(TAG, "event.getRawY()=============================" + event.getRawY());

                        LogUtil.e(TAG, "mContainerLastY============================="+mContainerLastY);


                        /****************************************
                         * 测试:父容器不再拦截,直接在touch事件里处理掉.如果需要分发,则手动调用子类的onTounch
                         * 如果左右滑动,分发
                         * 如果上下滑动,根据tab的位置判断是否分发
                         *
                         */
                       /* boolean isScrollUp=event.getRawY()<=mContainerLastY;//上滑
                        LogUtil.e(TAG, "上滑?"+isScrollUp);

                        boolean isHonrizonalScroll=Math.abs(Math.abs(event.getRawX())-Math.abs(mContainerActionDownX))>MyDispatchRelativeLayout.SCROLL_THRESHOLD;
                        LogUtil.e(TAG, "横向滑动?"+isHonrizonalScroll);

                        if(  mDispatchEventToRecyclerView || isHonrizonalScroll || !judgeIntercept(isScrollUp)  ){
                            mDispatchEventToRecyclerView=true;
                            mViewBind.vp.onTouchEvent(event);//教给vp去消费
                            //mViewBind.vp.getO;//教给vp去消费
                            return false;
                        }*/
                        /****************************************
                         * 测试:父容器不再拦截,直接在touch事件里处理掉.如果需要分发,则手动调用子类的onTounch
                         * 如果左右滑动,分发
                         * 如果上下滑动,根据tab的位置判断是否分发
                         *
                         */


                        int containerLastdY = (int) event.getRawY() - mContainerLastY;
                        LogUtil.e(TAG, "containerLastdY=============================" + containerLastdY);

                        mContainerSlidedDistance = (int) event.getRawY() - mContainerActionDownY;
                        LogUtil.e(TAG, "父容器滑动距离:mSlidedDistance=" + mContainerSlidedDistance);

                        final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
                        int left = params.leftMargin;
                        int top = params.topMargin;
                        int right = params.rightMargin;
                        int bottom = params.bottomMargin;

                        final ViewGroup.MarginLayoutParams vpParams = (ViewGroup.MarginLayoutParams) llHead.getLayoutParams();
                        //int left = vpParams.leftMargin;
                        //int top = vpParams.topMargin;
                        //int right = vpParams.rightMargin;
                        //int bottom =vpParams.bottomMargin;

                        LogUtil.e(TAG, "container:left:" + left + ",top:" + top + ",right:" + right + ",bottom" + bottom);

                        int topNew = top + containerLastdY;
                        int bottomNew = bottom - containerLastdY;

                        LogUtil.e(TAG, "container:topNew:" + topNew + ",bottomNew" + bottomNew);



                        //上滑极限是tab的位置,不可下滑(相对于初始位置来讲)!!!! topNew小于0是上滑  topNew大于0是下滑  by:Chuck 2018/05/23
                        if ((topNew <= 0 && Math.abs(topNew) <= mScroolMax)) {

                            if(topNew <= 0 && Math.abs(topNew) >= mScroolMax){//滑动超标了.因为回调并不是一个像素一个像素的
                                topNew=-1 * mScroolMax;//赋值为阈值
                            }

                            LogUtil.e(TAG, topNew + "container=============================MOVE");
                            params.setMargins(left, topNew, right, bottomNew);
                            v.setLayoutParams(params);

                            vpParams.setMargins(left, topNew, right, bottomNew);
                            llHead.setLayoutParams(vpParams);
                            mContainerLastY = (int) event.getRawY();

                            //重置顶部title的透明度
                            resetTitleAlpha(bottomNew);
                        }
                        /*else{//分发给viewpager ps:这样处理无效.结果就是,recyclerview在从底部滑到顶部时.需要松手再滑,才能使recyclerview滑到
                            vp.onTouchEvent(event);
                            mContainerLastY = (int) event.getRawY();
                            resetTitleAlpha(bottomNew);
                            return false;
                        }*/


                        break;

                    case MotionEvent.ACTION_UP://注意,全部是getRawX和getRawY
                        LogUtil.e(TAG, "MotionEvent.ACTION_UP");



                        //vp父容器的布局参数
                        final ViewGroup.MarginLayoutParams paramsVpUp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();

                        //head的布局参数
                        final ViewGroup.MarginLayoutParams paramsUp = (ViewGroup.MarginLayoutParams) llHead.getLayoutParams();

                        //上滑到一个临界值,container:left:0,top:-702,right:0,bottom702  则把它设置为悬浮状态
                        if(paramsUp.bottomMargin>0 && Math.abs(mScroolMax-paramsUp.bottomMargin)<=FLOAT_THRESHOLD_Y ){
                            paramsUp.setMargins(0, -1 * mScroolMax, 0,mScroolMax);
                            v.setLayoutParams(paramsUp);

                            paramsVpUp.setMargins(0,  -1 *mScroolMax, 0,mScroolMax);
                            rlVpContainner.setLayoutParams(paramsVpUp);

                            //重置顶部title的透明度
                            resetTitleAlpha(mScroolMax);
                        }

                        //下滑,如果手指抬起来时,tab的位置与初始值的位置的阈值在MARGIN_THRESHOLD范围内,则把一切还原
                        else if(Math.abs(paramsUp.topMargin)<=FLOAT_THRESHOLD_Y){//已经在底部,初始的位置
                            LogUtil.e(TAG, "tab在最底部,下滑,不拦截>>>recyclerView消费滑动事件");


                            paramsVpUp.setMargins(0, 0,0, 0);
                            v.setLayoutParams(paramsVpUp);

                            paramsUp.setMargins(0, 0, 0, 0);
                            llHead.setLayoutParams(paramsUp);

                            try {
                                CustomBaseFragment2 fragment = mPagerList.get(initIndex);
                                LogUtil.e(TAG, "返回顶部,fragment.isVisible()?" + fragment.isVisible());
                                if (fragment!=null&&fragment.isVisible()) {
                                    fragment.setSelection(0);//滑动到顶部
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                            //重置顶部title的透明度
                            resetTitleAlpha(0);
                        }




                        return true;
                    //break;


                    case MotionEvent.ACTION_CANCEL:
                        break;

                }
                return false;
            }
        });

    }

    /**
     * @method name:judgeIntercept
     * @des:是否拦截事件.true则拦截,拦截了则recyclerView滑动不了
     * @param :[isScrollUp]
     * @return type:boolean
     * @date 创建时间:2018/5/24
     * @author Chuck
     **/
    protected boolean judgeIntercept(boolean isScrollUp) {



        final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) llHead.getLayoutParams();

        int bottom = params.bottomMargin;

        LogUtil.e(TAG, "此时head的marginBottom:" + bottom);

        if (Math.abs(bottom-mScroolMax)<=MARGIN_THRESHOLD) {//满足这个条件,则表示,切换碎片的tab已经悬浮于顶部了,此时可以返回false,父容器不拦截,则子控件viewPager(里面是frgment)自行处理事件



            //return false;

            if (isScrollUp) {//上滑
                LogUtil.e(TAG, "tab在顶部,上滑,不拦截>>>recyclerView消费滑动事件");
                return false;
            } else {//下滑
                try {
                    CustomBaseFragment2 fragment = mPagerList.get(initIndex);
                    if (fragment!=null&&fragment.isHeadviewAtTopNow()) {//下滑,如果自定义的headview就在顶部,再下滑,就要返回true,不触发recyclerView的滑动事件
                        LogUtil.e(TAG, "tab在顶部,下滑,recyclerView的headview在顶部,拦截>>>父容器消费滑动事件");
                        return true;
                    } else {//headview不再顶部,则让recyclerview消费滑动事件
                        LogUtil.e(TAG, "tab在顶部,下滑,recyclerView的headview不在顶部,不拦截>>>recyclerView消费滑动事件");
                        return false;
                    }
                } catch (Exception e) {
                    LogUtil.e(TAG, "抛异常,拦截>>>父容器消费滑动事件");

                    e.printStackTrace();
                    return true;
                }
            }
        }
        else {
            if (isScrollUp) {//上滑,父类消费滑动事件
                LogUtil.e(TAG, "tab不在顶部,上滑,拦截>>>父容器消费滑动事件");

                return true;
            } else {//下滑
                if(Math.abs(params.topMargin)<=MARGIN_THRESHOLD){//已经在底部,初始的位置
                    LogUtil.e(TAG, "tab在最底部,下滑,不拦截>>>recyclerView消费滑动事件");
                    return  false;//
                }
                else{
                    LogUtil.e(TAG, "tab在中间,下滑,拦截>>>父容器消费滑动事件");
                    return true;
                }
            }
        }
    }


    private void resetTitleAlpha(int llHeadMarginBottom){

        LogUtil.i(TAG,"resetTitleAlpha:llHeadMarginBottom,="+llHeadMarginBottom);
        //原始值
        int orginalMarginBottom = 0;

        //滑动到limit时,把mainActivity的titile的alpha值设置为1
        int limit =mScroolMax;//tab处于顶部时的marginBottom

        float alpha = 0.0f;

        //llHeadMarginBottom     alpha
        //707                     1
        //600                     0.8
        //500                     0.5
        //330                     0.3
        //0                       0

        if (llHeadMarginBottom <= orginalMarginBottom) {
            alpha=0;
        } else if (llHeadMarginBottom > orginalMarginBottom && llHeadMarginBottom < limit) {//上滑
            alpha = 1.0f - (1.0f * (limit - llHeadMarginBottom) / (limit - orginalMarginBottom));
        } else if (llHeadMarginBottom >= limit) {
            alpha = 1.0f;
        }
        LogUtil.i(TAG,"resetTitleAlpha:alpha,="+alpha);

        ivBackground.setAlpha(alpha);



    }


    /**
     * @param :[]
     * @return type:void
     * @method name:getScroolMax
     * @des:初始化滑动阈值
     * @date 创建时间:2018/5/23
     * @author Chuck
     **/
    private void getScroolMax() {
        ViewTreeObserver viewTreeObserver = getView().getViewTreeObserver();
        if (viewTreeObserver != null) {//绘制完成的监听
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {

                    LogUtil.i(TAG,"onGlobalLayout()");
                    LogUtil.i(TAG,"onGlobalLayout(),屏幕总高度:"+DensityUtil.getDisplayHeight(getActivity()));

                    //如果虚拟物理键盘被隐藏了,这个应该会被回调.所以不再remove监听.只要界面有重绘,就重新设置viewPager的高度
                    getView().getViewTreeObserver().removeGlobalOnLayoutListener(this);//只需要监听一次,之后通过listener回调即可

                    //悬浮于顶部,距离值
                    mScroolMax =adList.getHeight()-rlTitleFilled.getHeight();

                    LogUtil.e(TAG, "能上滑的最大距离:" + mScroolMax);

                    //重置viewPager的最大高度:  注意:虚拟返回键被收起后,看看获得到的屏幕高度是否有变化
                    //rl_vp_containner  屏幕高度-title-tab-底部tab
                    //int maxHeight= DensityUtil.getDisplayHeight(getActivity()) - DensityUtil.dp2px(getActivity(),70+45+0);

                    //不再使用这种方式获取能滑动的最大高度,因为界面可能不包含状态栏
                    //int maxHeight= DensityUtil.getDisplayHeight(getActivity())-rlTitleFilled.getHeight()-mTabContainer.getHeight();

                    int maxHeight= rl_content_root.getHeight()-rlTitleFilled.getHeight()-mTabContainer.getHeight();
                    ViewGroup.LayoutParams pa=rlVpContainner.getLayoutParams();
                    pa.height=maxHeight;
                    LogUtil.i(TAG,"重置vp父容器的高度值:"+maxHeight);
                    rlVpContainner.setLayoutParams(pa);


                }
            });
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        LogUtil.e(TAG, "POSITION:" + position);
        initIndex = position;//重置position
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }


    /**
     * ViewPager适配器
     */
    public class MyViewPager extends FragmentPagerAdapter {

        public MyViewPager(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int arg0) {
            return mPagerList.get(arg0);
        }

        @Override
        public int getCount() {
            return mPagerList.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return "";
        }
    }

    /**
     * @method name:getFragmnets
     * @des:填充碎片
     * @param :[]
     * @return type:void
     * @date 创建时间:2018/5/29
     * @author Chuck
     **/
    private void getFragmnets() {
        /*for (int i = 0; i < mCropsBeans.size(); i++) {
            CateBean bean = mCropsBeans.get(i);//获取战队,传值进里面的fragment
            fragment = new HomeFragment();
            // TODO: 2017/9/15 碎片传参数
            Bundle bundle = new Bundle();
            bundle.putInt(HomeFragment.INTENT_KEY_CROPS_ID, bean.getCateId());
            fragment.setArguments(bundle);
            mPagerList.add(fragment);
        }*/




        mPagerList.addAll(getSubFragments());

        if (vp.getAdapter() == null) {
            //初始化ViewPager
            vp.setAdapter(new MyViewPager(getChildFragmentManager()));//注意fragmentAdapter的构造器
            vp.setOnPageChangeListener(this);

            LogUtil.e(TAG, "initIndex:" + initIndex);

            if(initIndex<0||initIndex>=mPagerList.size()){
                initIndex=0;
            }
            LogUtil.e(TAG, "initIndex:" + initIndex);

            vp.setCurrentItem(initIndex);

            //tab的初始化、tab和ViewPager的互相绑定
            //tabs.setSmoothScroll(false);
            //tabs.setViewPager(mViewBind.vp);
            //tabs.setOnPageChangeListener(this);
        }
    }










    /**
     * @method name:getTitleBackgroundRes
     * @des:title背景资源设置
     * @param :[]
     * @return type:int
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract int getTitleBackgroundRes();

    /**
     * @method name:getTitleView
     * @des:设置titleview.
     * @param :[]
     * @return type:android.view.View
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract View getTitleView();

    /**
     * @method name:getTitleViewParentHeight
     * @des:重置title父容器总高度(不包括getTitleView,因为getTitleView的父容器它有一个paddingTop)
     * @param :[]
     * @return type:int
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract int getTitleViewParentHeight();

    /**
     * @method name:getTitleViewMarginTop
     * @des:重置title父容器paddingTop,单位:像素
     * @param :[]
     * @return type:int
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract int getTitleViewMarginTop();

    /**
     * @method name:getHeadView
     * @des:顶部的"headview" 可以是包含 左右滑动的banner.滑动事件的分发逻辑已经处理了.左右滑动时.事件将被banner消费
     * @param :[]
     * @return type:android.view.View
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract  View getHeadView();

    /**
     * @method name:getFloatView
     * @des:悬浮控件设置,悬浮控件和底下viewpager的绑定,可以在onActivityCreated里添加
     * @param :[]
     * @return type:android.view.View
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract   View getFloatView();

    /**
     * @method name:getSubFragments
     * @des:设置子碎片,CustomBaseFragment2是自定义类,里面必须实现的是isHeadviewAtTopNow()
     * @param :[]
     * @return type:java.util.ArrayList<linklink.com.scrollview_within_recyclerview.base.CustomBaseFragment2>
     * @date 创建时间:2018/6/25
     * @author Chuck
     **/
    public  abstract   ArrayList<CustomBaseFragment2> getSubFragments();


}


PS:

这个库有个最大的问题,目前我也处理不好:

把Viewpager从初始位置滑动到顶部阈值时,如果继续滑动,里面的recyclerView是不会有动作的.因为此时父容器的已经开始在消费move事件了,我不知道当父容器在不断消费move事件的情况下,如何再次把事件"移交"给子控件处理.也就是说,demo里把下面的viewpager滑到顶部时,要松手再滑,里面的recyclerView才能滑动.如果哪位大神有方案,欢迎指导!



Github地址:

https://github.com/506954774/ScrollviewWithinRecyclerviewAndFloatView