NestedScrollView嵌套RecycleView 滑动 实现上滑隐藏 下滑显示头部效果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NestedScrollView嵌套RecycleView 滑动 实现上滑隐藏 下滑显示头部效果相关的知识,希望对你有一定的参考价值。

   废了好大的劲才弄好的,记下来 方便以后查看

   

public class MainActivity extends AppCompatActivity {


    private RecyclerView mRecyclerView;
    private List<String> mDatas;
    private HomeAdapter mAdapter;

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


        initData();

        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
//设置布局管理器
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置adapter
        mRecyclerView.setAdapter(mAdapter = new HomeAdapter());

    }

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

    class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> {

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
                    MainActivity.this).inflate(R.layout.item_home, parent,
                    false));
            return 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);
            }
        }
    }

 

  然后是最关键的NestedScrollview 是为了配合嵌套滑动的,  NestedScrollview最关键有两个接口的实现 一个是 NestedScrollingChild  一个是NestedScrollingParent

 

先是NestedScrollingParent

public class MyNestedScrollParent extends LinearLayout implements NestedScrollingParent {
    private String Tag = "MyNestedScrollParent";
    private View topView ;
    private View centerView;
    private View contentView;
    private MyNestedScrollChildL nsc ;
    private NestedScrollingParentHelper mParentHelper;
    private int imgHeight;
    private int tvHeight;
    private int mLastTouchY;
    public boolean topShow;

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

    public MyNestedScrollParent(Context context) {
        super(context);
        init();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        topView = getChildAt(0);
        centerView =  getChildAt(1);
        contentView = getChildAt(2);
        topView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if(imgHeight<=0){
                    imgHeight =  topView.getMeasuredHeight();
                    Log.i(Tag,"imgHeight:"+imgHeight+",tvHeight:"+tvHeight);
                }
            }
        });
        centerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                if(tvHeight<=0){
                    tvHeight =  centerView.getMeasuredHeight();
                    Log.i(Tag,"imgHeight:"+imgHeight+",tvHeight:"+tvHeight);
                }
            }
        });



    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(), topView.getMeasuredHeight() + centerView.getMeasuredHeight() + contentView.getMeasuredHeight());

    }
    public int  getTopViewHeight(){
        Log.i(Tag,"getTopViewHeight--"+topView.getMeasuredHeight());
        return topView.getMeasuredHeight();
    }

    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        Log.i(Tag,"onStartNestedScroll--"+"child:"+child+",target:"+target+",nestedScrollAxes:"+nestedScrollAxes);
        return true;
    }
    private void init() {
        mParentHelper = new NestedScrollingParentHelper(this);

    }

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

    @Override
    public void onStopNestedScroll(View target) {
        Log.i(Tag,"onStopNestedScroll--target:"+target);
        mParentHelper.onStopNestedScroll(target);
    }

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

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {

        if(showImg(dy)||hideImg(dy)){//如果父亲自己要滑动,则拦截
            consumed[1]=dy;
            scrollBy(0,dy);
            Log.i("onNestedPreScroll","Parent滑动:"+dy);
        }
        Log.i(Tag,"onNestedPreScroll--getScrollY():"+getScrollY()+",dx:"+dx+",dy:"+dy+",consumed:"+consumed);
    }

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

    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        Log.i(Tag,"onNestedPreFling--target:"+target);
        return false;
    }

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



    @Override
    public void scrollTo(int x, int y) {
        if(y<0){
            y=0;
        }
        if(y>imgHeight){
            y=imgHeight;
        }

        super.scrollTo(x, y);
    }

    /**
    下拉的时候是否要向下滑动显示图片
     */
    public boolean showImg(int dy){
        if(dy<0){

//            if(getScrollY()>0&&nsc.getScrollY()==0){//如果parent外框,还可以往上滑动
            if(getScrollY()>0){

                return true;
            }
        }


        return false;
    }



    /**
     * 上拉的时候,是否要向上滑动,隐藏图片
     * @return
     */
    public boolean hideImg(int dy){
        if(dy>0){
            if(getScrollY()<imgHeight){//如果parent外框,还可以往下滑动
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(event.getAction()==MotionEvent.ACTION_DOWN){
            return true;
        }
        return super.onTouchEvent(event);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        return super.onInterceptTouchEvent(event);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("aaa","getY():getRawY:"+event.getRawY());

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mLastTouchY = (int) (event.getRawY() + 0.5f);

                break;
            case MotionEvent.ACTION_MOVE:
                int y = (int) (event.getRawY() + 0.5f);
                int dy = mLastTouchY - y;
                mLastTouchY = y;
                if(showImg(dy)||hideImg(dy)){//如果父亲自己要滑动
                    scrollBy(0,dy);
                }
                break;
            case MotionEvent.ACTION_UP:

                break;
        }


        return super.dispatchTouchEvent(event);
    }

}

  然后是NestedScrollingChild

public class MyNestedScrollChild extends ScrollView implements NestedScrollingChild {
    private String Tag = "MyNestedScrollChild";
    private NestedScrollingChildHelper mScrollingChildHelper;


    public MyNestedScrollChild(Context context) {
        super(context);
        init(context);
    }

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

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

    public void init(Context context) {
        final ViewConfiguration configuration = ViewConfiguration.get(context);

    }

    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        Log.i(Tag, "setNestedScrollingEnabled:" + enabled);
        getScrollingChildHelper().setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        Log.i(Tag, "isNestedScrollingEnabled");
        return getScrollingChildHelper().isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes) {

        boolean bl = getScrollingChildHelper().startNestedScroll(axes);
        Log.i(Tag, "startNestedScroll:axes=" + axes + ",bl:" + bl);
        Log.i(Tag, "hasNestedScrollingParent=" + getScrollingChildHelper().hasNestedScrollingParent());
        return bl;
    }

    @Override
    public void stopNestedScroll() {
        Log.i(Tag, "stopNestedScroll");
        getScrollingChildHelper().stopNestedScroll();
    }

    @Override
    public boolean hasNestedScrollingParent() {
        Log.i(Tag, "hasNestedScrollingParent");
        return getScrollingChildHelper().hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
                                        int dyUnconsumed, int[] offsetInWindow) {
        Log.i(Tag, "dispatchNestedScroll:dxConsumed:" + dxConsumed + "," +
                "dyConsumed:" + dyConsumed + ",dxUnconsumed:" + dxUnconsumed + ",dyUnconsumed:" +
                dyUnconsumed + ",offsetInWindow:" + offsetInWindow);
        return getScrollingChildHelper().dispatchNestedScroll(dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
        Log.i(Tag, "dispatchNestedPreScroll:dx" + dx + ",dy:" + dy + ",consumed:" + consumed + ",offsetInWindow:" + offsetInWindow);
        return getScrollingChildHelper().dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        Log.i(Tag, "dispatchNestedFling:velocityX:" + velocityX + ",velocityY:" + velocityY + ",consumed:" + consumed);
        return getScrollingChildHelper().dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        Log.i(Tag, "dispatchNestedPreFling:velocityX:" + velocityX + ",velocityY:" + velocityY);
        return getScrollingChildHelper().dispatchNestedPreFling(velocityX, velocityY);
    }

    private NestedScrollingChildHelper getScrollingChildHelper() {
        if (mScrollingChildHelper == null) {
            mScrollingChildHelper = new NestedScrollingChildHelper(this);
            mScrollingChildHelper.setNestedScrollingEnabled(true);
        }
        return mScrollingChildHelper;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(),getMeasuredHeight()+((MyNestedScrollParent)getParent()).getTopViewHeight());
    }
}

  

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="com.lmj.com.mynestscroll.MainActivity">


    <com.lmj.com.mynestscroll.view.MyNestedScrollParent
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#0f0"
        android:clickable="true"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >


            <TextView
                android:id="@+id/tv_search"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="center"
                android:padding="20dp"
                android:text="搜索" />

            <LinearLayout
                android:id="@+id/ll_other"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginLeft="20dp"
                android:layout_marginRight="20dp"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="#30ffffff"
                    android:drawablePadding="10dp"
                    android:gravity="center_vertical"
                    android:padding="10dp"
                    android:text="任何地方"
                    android:textColor="#fff" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:background="#30ffffff"
                    android:drawablePadding="10dp"
                    android:padding="10dp"
                    android:text="任何时间"
                    android:textColor="#fff" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:background="#30ffffff"
                    android:drawablePadding="10dp"
                    android:padding="10dp"
                    android:text="房客"
                    android:textColor="#fff" />

            </LinearLayout>
        </LinearLayout>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#f0f"
            android:text="@string/topStr" />

        <com.lmj.com.mynestscroll.view.MyNestedScrollChild
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent" 
                android:text="1231231231312"
                />
            
        </com.lmj.com.mynestscroll.view.MyNestedScrollChild>
        
        
        
       <!--<com.lmj.com.mynestscroll.MyRecycleView-->
           <!--android:id="@+id/id_recyclerview"-->
           <!--android:layout_width="match_parent"-->
           <!--android:layout_height="match_parent">-->


       <!--</com.lmj.com.mynestscroll.MyRecycleView>-->

    </com.lmj.com.mynestscroll.view.MyNestedScrollParent>


</RelativeLayout>
NestedScrollingChild和NestedScrollingParent之间的部分,在滑动时会悬浮在顶部 而RecycleView 本身已经实现了NestedScrollingChild

我们在使用RecycleView的时候 需要重写
onMeasure方法
public class MyRecycleView extends RecyclerView {
    public MyRecycleView(Context context) {
        super(context);
    }

    public MyRecycleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        super.onMeasure(widthSpec, heightSpec);
        setMeasuredDimension(getMeasuredWidth(),getMeasuredHeight()+((MyNestedScrollParent)getParent()).getTopViewHeight());
    }
}

重新设定RecycleView的高度

 

以上是关于NestedScrollView嵌套RecycleView 滑动 实现上滑隐藏 下滑显示头部效果的主要内容,如果未能解决你的问题,请参考以下文章

PHP.DHN透过 NestedScrollView 源码解析嵌套滑动原理-附教程

PHP.DHN透过 NestedScrollView 源码解析嵌套滑动原理-附教程

Android番外篇 NestedScrollView嵌套RecyclerView

Android之解决NestedScrollView嵌套RecyclerView部分手机返回到这个页面Recyclerview顶部,而不是页面NestedScrollView顶部

Android之解决NestedScrollView嵌套RecyclerView部分手机返回到这个页面Recyclerview顶部,而不是页面NestedScrollView顶部

NestedScrollView嵌套ListView滑动冲突