RecyclerView下拉刷新 上拉加载 原理Demo

    xiaoxiao2021-03-26  17

    RecycleView作为Android5.0谷歌对ListView的升级版,其强大之处是:比ListView更为轻量,使用得当的话,完全可以替代ListView/GridView。本节主要说明添加刷新头的原理。首先我们先来熟悉一下RecycleView的简单使用吧。

    recycleView的用法:

    1.因为RecycleView在V7包里面有引入,所以我们要导入正确的v7包(后缀带有recycle的v7包);  //设置布局管理器         rvMain.setLayoutManager(new LinearLayoutManager(this));         //设置adapter         rvMain.setAdapter(new HomeAdapter());         //设置Item增加、移除动画         rvMain.setItemAnimator(new DefaultItemAnimator());         //添加分割线         rvMain.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); 2.该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况

    注意:这里的布局管理器有三种,

    rvMain.setLayoutManager(new LinearLayoutManager(this)); //rvMain.setLayoutManager(new GridLayoutManager(this,4)); //rvMain.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL));

    大家可以分别设置一下看看效果,自己去尝试一下总比我在这里演示要我,问题也不难。简单繁琐的事情我这里就略过了。

    但是我要告诉大家的是如果你仅仅是改变布局管理器而不去改写分割线的话效果是明显不美观的。大家可以参考鸿洋大神重写分割线

    的博文,很详细。

    recycleViewAdapter的方法概要:

    玩过Android开发的小伙伴都应该知道ListView这玩意吧,但是到了RecyclerView这里好像就不像ListView一样提供一个

    addHeaderView的方法。那么我们如何实现这个效果呢?

    下拉加载跟多原理: 首先我们要了解RecycleViewAdapter的以下方法 @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (TYPE_REFRESH_HEADER==viewType){ return new LViewHolder(mRefreshHeader.getHeaderView()); }else{ return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_rvmain, parent, false)); } } @Override public void onBindViewHolder( RecyclerView.ViewHolder holder,int position) { if (!isRefreshHeader(position)){ ((MyViewHolder)holder).tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(mContext, String.valueOf("aa"),Toast.LENGTH_SHORT).show(); Intent intent = new Intent(mContext ,CoordinatorActivity.class); mContext.startActivity(intent); } }); ((MyViewHolder)holder).tv.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { Toast.makeText(mContext, String.valueOf("aa")+"---LONG",Toast.LENGTH_SHORT).show(); return true; } }); } } @Override public int getItemCount() { return 20; } @Override public int getItemViewType(int position) { if (isRefreshHeader(position)) { return TYPE_REFRESH_HEADER; } return TYPE_NORMAL; } 这里我们主要关心getItemViewType和OnCreatViewHolder这两个方法,我们可以看到 getItemViewType可以根据item的position 返回一个Type,然后我们在OnCreatViewHolder这个方法就可以根据Type这个类型来返回一个特定的Viewholder。换句话说就是我们 可以自己定义每一一个Item 样式。这不相当于我们有了刷新头么,关键是我们如何动态去控制这个Item(刷新头)的高度?我想是这样的:重写RecycleView的OnEventTouch方法然后动态控制刷新头的高度。先上效果给大家看看 1.我们自定义一个View作为刷新头,即RecycleView的第一个Item。这个自定义的View必须对外提供设置高度,状态,动态滑动效果等等方法,而且初始化高度为0。 主要实现一个接口提供下满方法 public interface IRefreshHeader { int STATE_NORMAL = 0; int STATE_RELEASE_TO_REFRESH = 1; int STATE_REFRESHING = 2; int STATE_DONE = 3; void onReset(); /** * 下拉移动 */ void onMove(float offSet, float sumOffSet); /** * 处于可以刷新的状态,已经过了指定距离 */ void onPrepare(); /** * 下拉松开 */ boolean onRelease(); /** * 正在刷新 */ void onRefreshing(); /** * 下拉刷新完成 */ void refreshComplete(); /** * 获取HeaderView */ View getHeaderView(); /** * 获取Header的显示高度 */ int getVisibleHeight(); } 2.重写RecycleView的OnTouchEvent方法如下: @Override public boolean onTouchEvent(MotionEvent e) { if (mLastY == -1) { mLastY = e.getRawY(); } int action =e.getAction(); switch (action){ case MotionEvent.ACTION_DOWN: mLastY = e.getRawY(); sumOffSet = 0; break; case MotionEvent.ACTION_MOVE: final float deltaY = (e.getRawY() - mLastY) / DRAG_RATE; mLastY = e.getRawY(); sumOffSet += deltaY; //动态设置第一个Item的高度,即刷新头 mRefreshHeader.onMove(deltaY, sumOffSet); Log.v("ACTION_MOVE","-------------------"+deltaY); if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshing) { return false; } break; // case MotionEvent.ACTION_UP: // break; // case MotionEvent.ACTION_CANCEL: // break; default://当滑动松开时,刷新头滑动到刷新状态 if (mRefreshHeader.onRelease()) { if (mRefreshListener != null) { mFootView.setVisibility(GONE); mRefreshing = true; //刷新状态的回调,加载数据的过程 mRefreshListener.onRefresh(); } } } return super.onTouchEvent(e); } 3.主页面主要逻辑 public void BasicUse(){ //设置布局管理器 rvMain.setLayoutManager(new LinearLayoutManager(this)); //rvMain.setLayoutManager(new GridLayoutManager(this,4)); //rvMain.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)); //设置adapter rvMain.setAdapter(new LRecyclerViewAdapter(MainActivity.this)); //设置Item增加、移除动画 rvMain.setItemAnimator(new DefaultItemAnimator()); //添加分割线 // rvMain.addItemDecoration(new DividerItemDecoration( // this, DividerItemDecoration.VERTICAL)); rvMain.addItemDecoration(new DividerGridItemDecoration( MainActivity.this)); rvMain.setOnRefreshListener(new OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable(){ public void run() { //这里作网络数据请求提供的方法,但我没有处理 //当数据刷新后我们调用下面的方法把正在刷新状态下的刷新头的高度和状态改变 rvMain.refreshComplete(10); } }, 1200); } }); } 上拉加载更多原理: 效果图: 1.首先我們要想如何確定Adapter最後一個肯定是加載更多的那個控件。但是我們如何去確定呢?我想法事這樣的,首先把加載更多這個控件設置到 Adapter裏面,然後根據檢測到最後一個位置則添加加載更多這個控件,這樣最後一個item永遠是加載更多這個控件,但是我們接下來想的就是如何 控制這個控件的高度和可見性。這個就是觸發加載更多事件入口? 这里我们需要搞懂的就是RecycleView的滚动事件了。列表的滚动过程一般分两种: (1)手指按下 -->手指拖拽滑动--> 手指停止--> 手指抬起 (2)手指按下--> 手指快速拖拽后抬起 --> 列表继续滑动 -->手指抬起 而上面这两种滚动过程所持有的状态是在RecycleView的OnScrollStateChange(int state)这个方法记录,而且上面两种滚动的整个过程都是表现为 3重状态。分别为 1 -->2 -->0(开始滚动,正在滚动,停止滚动)。只要我们在停止滚动是判断最后一个可见item是否最后一个就可以了,如果是就 加载。 2.RecycleView中触发加载如下: @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); currentScrollState = state; Log.d("------------", "onScrollStateChanged: onScrollStateChanged--------------"+state); if (mLScrollListener != null) { mLScrollListener.onScrollStateChanged(state); } if (mLoadMoreListener != null && mLoadMoreEnabled) { if (currentScrollState == RecyclerView.SCROLL_STATE_IDLE) { RecyclerView.LayoutManager layoutManager = getLayoutManager(); int visibleItemCount = layoutManager.getChildCount(); int totalItemCount = layoutManager.getItemCount(); if (visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 && totalItemCount > visibleItemCount && !mRefreshing) { mFootView.setVisibility(View.VISIBLE); if (mLoadingData) { return; } else { mLoadingData = true; mLoadMoreFooter.onLoading(); mLoadMoreListener.onLoadMore(); } 3.dapter的改写 @Override public int getItemViewType(int position) { // if (isRefreshHeader(position)) { // return TYPE_REFRESH_HEADER; // } // return TYPE_NORMAL; // int adjPosition = position - (getHeaderViewsCount() + 1); if (isRefreshHeader(position)) { return TYPE_REFRESH_HEADER; } // if (isHeader(position)) { // position = position - 1; // return mHeaderTypes.get(position); // } if (isFooter(position)) { return TYPE_FOOTER_VIEW; } // int adapterCount; // if (mInnerAdapter != null) { // adapterCount = mInnerAdapter.getItemCount(); // if (adjPosition < adapterCount) { // return mInnerAdapter.getItemViewType(adjPosition); // } // } return TYPE_NORMAL; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (TYPE_REFRESH_HEADER==viewType){ return new LViewHolder(mRefreshHeader.getHeaderView()); } else if (viewType == TYPE_FOOTER_VIEW) { return new LViewHolder(mFooterViews.get(0)); } else { return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_rvmain, parent, false)); } 3.主页面逻辑 rvMain.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { new Handler().postDelayed(new Runnable() { public void run() { //这里作网络数据请求提供的方法,但我没有处理 //当数据刷新后我们调用下面的方法把正在刷新状态下的刷新头的高度和状态改变 rvMain.setNoMore(true); } }, 1200); } }); 这里只是简单的介绍了RecycleView下拉刷新和上拉加载的基本原理,离真实项目开发用到还有很长一段距离要走呢。接下来我会整理一下这个Demo 然后给大家参考,如果大家有好的关于RecycleView的框架介绍也可以给我参考。

    转载请注明原文地址: https://ju.6miu.com/read-450348.html

    最新回复(0)