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顶部