赞
踩
本文参考辉哥的博客RecyclerView更全解析之 - 打造通用的下拉刷新上拉加载进行实现,具体代码实现思路可查看原博客,目的是通过自定义RecyclerView
自己实现添加头部
、添加底部
、上拉加载
、下拉刷新
功能。
/** - 支持添加头部和底部的Adapter - on 2022/11/7 */ class WrapRecyclerAdapter(adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { /** * 用来存放头部和底部的集合 */ private var headerView: SparseArray<View> private var footerView: SparseArray<View> //头部类型开始位置,用于viewType private var BASE_ITEM_TYPE_HEADER = 1000000 //底部类型开始位置,用于viewType private var BASE_ITEM_TYPE_FOOTER = 2000000 /** * 列表的adapter */ private var adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> init { this.adapter = adapter headerView = SparseArray() footerView = SparseArray() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { if (isHeaderViewType(viewType)) { val headerView = headerView.get(viewType) return createHeaderFooterViewHolder(headerView) } if (isFooterViewType(viewType)) { val footerView = footerView.get(viewType) return createHeaderFooterViewHolder(footerView) } return adapter.onCreateViewHolder(parent, viewType) } /** * 创建头部或底部的ViewHolder */ private fun createHeaderFooterViewHolder(view: View): RecyclerView.ViewHolder { return object : RecyclerView.ViewHolder(view) {} } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { //如果是头部或者底部item,不进行布局绑定 if (isHeaderViewPosition(position) || isFooterViewPosition(position)) { return } val itemAdapterPosition = position - headerView.size() adapter.onBindViewHolder(holder, itemAdapterPosition) } override fun getItemViewType(position: Int): Int { if (isHeaderViewPosition(position)) { //如果是headerView return headerView.keyAt(position) } if (isFooterViewPosition(position)) { //如果是footerView val footerPosition = position - headerView.size() - adapter.itemCount return footerView.keyAt(footerPosition) } //则为普通adapter的ViewType val adapterPosition = position - headerView.size() return adapter.getItemViewType(adapterPosition) } override fun getItemCount(): Int { //条目为三者数量之和 return adapter.itemCount + headerView.size() + footerView.size() } fun addHeaderView(view: View) { val position = headerView.indexOfValue(view) if (position < 0) { headerView.put(BASE_ITEM_TYPE_HEADER++, view) } notifyDataSetChanged() } fun removeHeaderView(view: View) { val position = headerView.indexOfValue(view) if (position < 0) { return } headerView.removeAt(position) notifyDataSetChanged() } fun getAdapter(): RecyclerView.Adapter<ViewHolder> { return adapter } fun addFooterView(view: View) { val position = footerView.indexOfValue(view) if (position < 0) { footerView.put(BASE_ITEM_TYPE_FOOTER++, view) } notifyDataSetChanged() } fun removeFooterView(view: View) { val position = footerView.indexOfValue(view) if (position < 0) { return } footerView.removeAt(position) notifyDataSetChanged() } private fun isHeaderViewType(viewType: Int): Boolean { val position = headerView.indexOfKey(viewType) return position >= 0 } private fun isFooterViewType(viewType: Int): Boolean { val position = footerView.indexOfKey(viewType) return position >= 0 } private fun isHeaderViewPosition(position: Int): Boolean { return position < headerView.size() } private fun isFooterViewPosition(position: Int): Boolean { return position >= headerView.size() + adapter.itemCount } /** * 解决GridLayoutManager添加头部和底部不占用一行的问题 */ fun adjustSpanSize(recyclerView: RecyclerView) { if (recyclerView.layoutManager is GridLayoutManager) { val layoutManager = recyclerView.layoutManager as GridLayoutManager layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { val isHeaderOrFooter = isHeaderViewPosition(position) || isFooterViewPosition(position) return if (isHeaderOrFooter) { layoutManager.spanCount } else { 1 } } } } }
/** - 可以添加头部和底部的RecyclerView - on 2022/11/7 */ open class WrapRecyclerView : RecyclerView { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) /** * 包裹了头部和底部的adapter */ private var wrapRecyclerAdapter: WrapRecyclerAdapter? = null /** * 列表对应的list */ private var mAdapter: Adapter<ViewHolder>? = null /** * 增加一些通用功能 * 空列表数据应该显示emptyView * 正在加载数据页面 */ private var emptyView: View? = null private var loadView: View? = null private var mDataObserver = object : AdapterDataObserver() { override fun onChanged() { if (mAdapter == null) { return } //观察者,列表adapter更新,包裹的也需要更新 if (wrapRecyclerAdapter != adapter) { wrapRecyclerAdapter?.notifyDataSetChanged() } dataChanged() } override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { if (mAdapter == null) { return } if (wrapRecyclerAdapter != adapter) { wrapRecyclerAdapter?.notifyItemRangeRemoved(positionStart, itemCount) } dataChanged() } override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { if (mAdapter == null) { return } if (wrapRecyclerAdapter != adapter) { wrapRecyclerAdapter?.notifyItemChanged(positionStart, itemCount) } dataChanged() } override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) { if (mAdapter == null) { return } if (wrapRecyclerAdapter != adapter) { wrapRecyclerAdapter?.notifyItemRangeChanged(positionStart, itemCount, payload) } dataChanged() } override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { if (mAdapter == null) { return } if (wrapRecyclerAdapter != adapter) { wrapRecyclerAdapter?.notifyItemRangeInserted(positionStart, itemCount) } dataChanged() } override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) { if (mAdapter == null) { return } if (wrapRecyclerAdapter != adapter) { wrapRecyclerAdapter?.notifyItemRangeRemoved(fromPosition, toPosition) } dataChanged() } } private fun dataChanged() { if (adapter?.itemCount == 0) { emptyView?.visibility = VISIBLE } } fun addEmptyView(view: View) { this.emptyView = view } fun addLoadingView(loadingView: View) { this.loadView = loadingView loadingView.visibility = VISIBLE } override fun setAdapter(adapter: Adapter<*>?) { //防止多次设置Adapter if (mAdapter != null) { mAdapter!!.unregisterAdapterDataObserver(mDataObserver) mAdapter = null } this.mAdapter = adapter as Adapter<ViewHolder>? wrapRecyclerAdapter = if (adapter is WrapRecyclerAdapter) { adapter } else { WrapRecyclerAdapter(adapter as Adapter<ViewHolder>) } super.setAdapter(wrapRecyclerAdapter) //注册一个观察者 mAdapter!!.registerAdapterDataObserver(mDataObserver) //解决GridLayoutManager添加头部和底部不占据一行问题 wrapRecyclerAdapter!!.adjustSpanSize(this) //加载数据页面 if (loadView != null && loadView!!.visibility == View.VISIBLE) { loadView?.visibility = GONE } } /** * 添加头部 */ fun addHeaderView(view: View) { wrapRecyclerAdapter?.addHeaderView(view) } /** * 添加底部 */ fun addFooterView(view: View) { wrapRecyclerAdapter?.addFooterView(view) } fun removeHeaderView(view: View) { wrapRecyclerAdapter?.removeHeaderView(view) } fun removeFooterView(view: View) { wrapRecyclerAdapter?.removeFooterView(view) }
/** - 下拉刷新的辅助类 - on 2022/11/7 */ abstract class RefreshViewCreator { /** * 获取下拉刷新的View * @param context 上下文参数 * @param parent 父容器 RecyclerView */ abstract fun getRefreshView(context: Context, parent: ViewGroup): View /** * 正在下拉 * @param currentDragHeight 当前拖动的高度 * @param refreshViewHeight 整体刷新View的高度 * @param currentRefreshStatus 当前状态 * */ abstract fun onPull(currentDragHeight: Int, refreshViewHeight: Int, currentRefreshStatus: Int) /** * 正在刷新中 */ abstract fun onRefreshing() /** * 停止刷新 */ abstract fun onStopRefresh() }
RefreshRecyclerView
/** - 下拉刷新的RecyclerView - on 2022/11/7 */ open class RefreshRecyclerView : WrapRecyclerView { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) //下拉刷新的辅助类 private var refreshCreator: RefreshViewCreator? = null //下拉刷新头部的高度 private var refreshViewHeight = 0 //下拉刷新的头部View private var refreshView: View? = null //手指按下Y的位置 private var fingerDownY = 0 //手指拖拽的阻力指数 open var dragIndex = 0.35f //当前是否正在拖动 private var currentDrag = false //当前状态 private var currentRefreshStatus = 0 // 默认状态 private val REFRESH_STATUS_NORMAL = 1 //下拉刷新状态 private val REFRESH_STATUS_PULL_DOWN_REFRESHING = 2 //松开刷新状态 private val REFRESH_STATUS_LOOSEN_REFRESHING = 3 //正在刷新状态 private val REFRESH_STATUS_REFRESHING = 4 fun addRefreshViewCreator(refreshViewCreator: RefreshViewCreator) { this.refreshCreator = refreshViewCreator addRefreshView() } override fun setAdapter(adapter: Adapter<*>?) { super.setAdapter(adapter) addRefreshView() } override fun dispatchTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_DOWN -> { //记录手指按下的位置 fingerDownY = ev.rawY.toInt() } MotionEvent.ACTION_UP -> { if (currentDrag) { restoreRefreshView() } } } return super.dispatchTouchEvent(ev) } /** * 重置当前刷新状态 */ private fun restoreRefreshView() { val currentTopMargin = (refreshView?.layoutParams as MarginLayoutParams).topMargin var finalTopMargin = -refreshViewHeight + 1 if (currentRefreshStatus == REFRESH_STATUS_LOOSEN_REFRESHING) { finalTopMargin = 0 currentRefreshStatus = REFRESH_STATUS_REFRESHING refreshCreator?.onRefreshing() listener?.onRefresh() } val distance = currentTopMargin - finalTopMargin //回弹到指定位置 val animator: ValueAnimator = ObjectAnimator.ofFloat(currentTopMargin.toFloat(), finalTopMargin.toFloat()) .setDuration(distance.toLong()) animator.addUpdateListener { val currentTopMargin = it.animatedValue as Float setRefreshViewMarginTop(currentTopMargin.toInt()) } animator.start() currentDrag = false } override fun onTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_MOVE -> { //在最顶部的时候才处理,否则不需要处理 if (canScrollUp() || currentRefreshStatus == REFRESH_STATUS_REFRESHING || refreshView == null || refreshCreator == null) { //如果没有到达最顶端,也就是说还可以向上滚动就什么都不处理 return super.onTouchEvent(ev) } //解决下拉刷新自动滚动问题 if (currentDrag) { scrollToPosition(0) } //获取手指触摸拖拽的距离 val distanceY = (ev.rawY - fingerDownY) * dragIndex //如果是已经到达头部,并且不断的向上拉,那么不断的改变refreshView的marginTop的值 if (distanceY > 0) { val marginTop = distanceY - refreshViewHeight setRefreshViewMarginTop(marginTop.toInt()) updateRefreshStatus(distanceY) currentDrag = true return false } } } return super.onTouchEvent(ev) } /** * 更新刷新状态 */ private fun updateRefreshStatus(distanceY: Float) { currentRefreshStatus = if (distanceY <= 0) { REFRESH_STATUS_NORMAL } else if (distanceY < refreshViewHeight) { REFRESH_STATUS_PULL_DOWN_REFRESHING } else { REFRESH_STATUS_LOOSEN_REFRESHING } refreshCreator?.onPull(distanceY.toInt(), refreshViewHeight, currentRefreshStatus) } /** * 添加头部刷新View */ private fun addRefreshView() { if (adapter != null && refreshCreator != null) { val refreshView = refreshCreator?.getRefreshView(context, this) if (refreshView != null) { addHeaderView(refreshView) this.refreshView = refreshView } } } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { super.onLayout(changed, l, t, r, b) if (refreshView != null && refreshViewHeight <= 0) { //获取头部刷新View的高度 refreshViewHeight = refreshView?.measuredHeight!! if (refreshViewHeight > 0) { //隐藏头部刷新的View marginTop 多留出1px防止无法判断是不是滑动到头部问题 setRefreshViewMarginTop(-refreshViewHeight + 1) } } } private fun setRefreshViewMarginTop(marginTop: Int) { var finalMarginTop = marginTop val params = refreshView?.layoutParams as MarginLayoutParams if (finalMarginTop < -refreshViewHeight + 1) { finalMarginTop = -refreshViewHeight + 1 } params.topMargin = finalMarginTop refreshView?.layoutParams = params } private fun canScrollUp(): Boolean { return canScrollVertically(-1) || scrollY > 0 } fun onStopRefresh() { currentRefreshStatus = REFRESH_STATUS_NORMAL restoreRefreshView() refreshCreator?.onStopRefresh() } private var listener: OnRefreshListener? = null fun setOnRefreshListener(listener: OnRefreshListener) { this.listener = listener } interface OnRefreshListener { fun onRefresh() }
/** * on 2022/11/7 */ class CommonRefreshCreator : RefreshViewCreator() { private var refreshView: View? = null override fun getRefreshView(context: Context, parent: ViewGroup): View { val view = LayoutInflater.from(context).inflate(R.layout.layout_progressbar, parent,false) refreshView = view.findViewById(R.id.pb) return view } override fun onPull(currentDragHeight: Int, refreshViewHeight: Int, currentRefreshStatus: Int) { val rotate = currentDragHeight / refreshViewHeight //不断下拉的过程中不断旋转图片 refreshView!!.rotation = (rotate * 360).toFloat() } override fun onRefreshing() { //刷新的时候也不断旋转 val animation = RotateAnimation( 0f, 720f, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5f ) animation.repeatCount = -1 animation.duration = 2000 refreshView!!.startAnimation(animation) } override fun onStopRefresh() { //停止的时候清除动画 refreshView!!.rotation = 0f refreshView!!.clearAnimation() } } ### layout_progressbar <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp"> <ProgressBar android:indeterminateDuration="1000" android:max="360" android:id="@+id/pb" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerInParent="true" /> </RelativeLayout>
/** - 支持上拉加载 下拉刷新的RecyclerView - on 2022/11/7 */ class LoadRefreshRecyclerView : RefreshRecyclerView { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) //上拉加载更多的辅助类 private var loadViewCreator: LoadViewCreator? = null //上拉加载更多头部的高度 private var loadViewHeight = 0 //上拉加载更多的头部View private var loadView: View? = null //手指按下的位置 private var fingerDownY = 0 //当前是否正在拖动 private var currentDrag = false //当前状态 private var currentLoadStatus = 0 companion object{ //默认状态 var LOAD_STATUS_NORMAL = 10 //上拉加载更多状态 var LOAD_STATUS_PULL_DOWN_REFRESH = 11 //松开加载更多状态 var LOAD_STATUS_LOOSEN_LOADING = 12 //正在加载更多状态 var LOAD_STATUS_LOADING = 13 } //设置上拉加载更多 fun addLoadViewCreator(loadViewCreator: LoadViewCreator) { this.loadViewCreator = loadViewCreator addLoadView() } override fun setAdapter(adapter: Adapter<*>?) { super.setAdapter(adapter) addLoadView() } override fun dispatchTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_DOWN -> { //记录手指按下的位置,之所以写在dispatchTouchEvent里是因为如果我们处理了item点击事件,那么就不会进入onTouchEvent里面,所有应该在这里处理 fingerDownY = ev.rawY.toInt() } MotionEvent.ACTION_UP -> { if (currentDrag) { restoreLoadView() } } } return super.dispatchTouchEvent(ev) } /** * 重置上拉加载更多View */ private fun restoreLoadView() { var currentBottomMargin = (loadView?.layoutParams as MarginLayoutParams).bottomMargin var finalBottomMargin = 0 if (currentLoadStatus == LOAD_STATUS_LOOSEN_LOADING) { currentLoadStatus = LOAD_STATUS_LOADING loadViewCreator?.onLoading() listener?.onLoad() } val distance = currentBottomMargin - finalBottomMargin //回弹到指定位置 val animator = ObjectAnimator.ofFloat(currentBottomMargin.toFloat(), finalBottomMargin.toFloat()) .setDuration(distance.toLong()) animator.addUpdateListener { val currentTopMargin = it.animatedValue setLoadViewMarginBottom(currentTopMargin as Float) } animator.start() currentDrag = false } override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { super.onLayout(changed, l, t, r, b) if (loadViewCreator != null && loadView != null) { loadViewHeight = loadView!!.measuredHeight } } override fun onTouchEvent(ev: MotionEvent): Boolean { when (ev.action) { MotionEvent.ACTION_MOVE -> { //当在最底部的时候才处理,否则不需要处理 if (canScrollDown() || currentLoadStatus == LOAD_STATUS_LOADING) { return super.onTouchEvent(ev) } //解决上拉加载更多自动滚动问题 if (currentDrag) { scrollToPosition(adapter!!.itemCount - 1) } //获取手指触摸拖拽的距离 val distanceY = (ev.rawY - fingerDownY) * dragIndex //如果是已经到达底部,并且不断的向下拉,那么不断的改变marginBottom的值 if (distanceY < 0) { setLoadViewMarginBottom(-distanceY) updateLoadStatus(-distanceY) currentDrag = true return true } } } return super.onTouchEvent(ev) } /** * 设置加载View的marginBottom */ private fun setLoadViewMarginBottom(marginBottom: Float) { var finalMarginBottom = marginBottom.toInt() val marginLayoutParams = loadView!!.layoutParams as MarginLayoutParams if (finalMarginBottom < 0) { finalMarginBottom = 0 } marginLayoutParams.bottomMargin = finalMarginBottom loadView?.layoutParams = marginLayoutParams } private fun canScrollDown(): Boolean { return canScrollVertically(1) } /** * 停止加载更多 */ fun onStopLoad() { currentLoadStatus = LOAD_STATUS_NORMAL restoreLoadView() loadViewCreator?.onStopLoad() } private fun updateLoadStatus(distanceY: Float) { currentLoadStatus = if (distanceY <= 0) { LOAD_STATUS_NORMAL } else if (distanceY < loadViewHeight) { LOAD_STATUS_PULL_DOWN_REFRESH } else { LOAD_STATUS_LOOSEN_LOADING } loadViewCreator?.onPull(distanceY.toInt(), loadViewHeight, currentLoadStatus) } private fun addLoadView() { if (adapter != null && loadViewCreator != null) { //添加底部加载更多View val view = loadViewCreator?.getLoadView(context, this) if (view != null) { addFooterView(view) this.loadView = view } } } private var listener: OnLoadMoreListener? = null fun setOnLoadMoreListener(listener: OnLoadMoreListener) { this.listener = listener } interface OnLoadMoreListener { fun onLoad() } }
/** - 上拉加载更多辅助类 - on 2022/11/8 */ abstract class LoadViewCreator { /** * 获取上拉加载更多的View */ abstract fun getLoadView(context: Context, parent: ViewGroup): View /** * 正在上拉 * @param currentDragHeight 当前拖动的距离 * @param loadViewHeight 总的加载高度 * @param currentLoadStatus 当前状态 */ abstract fun onPull(currentDragHeight: Int, loadViewHeight: Int, currentLoadStatus: Int) /** * 正在加载中 */ abstract fun onLoading() /** * 停止加载 */ abstract fun onStopLoad() }
class CommonLoadCreator : LoadViewCreator() { private var tv: TextView? = null private var pb: ProgressBar? = null private var loadView: View? = null override fun getLoadView(context: Context, parent: ViewGroup): View { val loadView: View = LayoutInflater.from(context).inflate(R.layout.layout_load_footer_view, parent, false) tv = loadView.findViewById(R.id.tv) pb = loadView.findViewById(R.id.pb) this.loadView = loadView return loadView } override fun onPull(currentDragHeight: Int, loadViewHeight: Int, currentLoadStatus: Int) { if (currentLoadStatus == LoadRefreshRecyclerView.LOAD_STATUS_PULL_DOWN_REFRESH) { tv?.text = "上拉加载更多" } if (currentLoadStatus == LoadRefreshRecyclerView.LOAD_STATUS_LOOSEN_LOADING) { tv?.text = "松开加载更多" } } override fun onLoading() { tv?.visibility = View.GONE pb?.visibility = View.VISIBLE val animation = RotateAnimation( 0f, 720f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f ) animation.duration = 2000 animation.repeatCount = -1 pb?.startAnimation(animation) } override fun onStopLoad() { //停止加载的时候 pb?.rotation = 0f pb?.clearAnimation() pb?.visibility = View.GONE tv?.text = "上拉加载更多" tv?.visibility = View.VISIBLE } } ### layout_load_footer_view <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center"> <ProgressBar android:id="@+id/pb" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:indeterminateDuration="1000" android:max="360" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:layout_toRightOf="@+id/pb" android:text="上拉加载更多" /> </RelativeLayout>
class RecyclerActivity : AppCompatActivity() { private val list = mutableListOf<String>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_recycler) for (i in 0..50) { list.add("$i") } val rlv = findViewById<LoadRefreshRecyclerView>(R.id.rlv) rlv.layoutManager = GridLayoutManager(this, 4) val adapter = CommonItemAdapter(this, list) rlv.adapter = adapter val headerView = LayoutInflater.from(this).inflate(R.layout.layout_recycler_header, rlv, false) val footerView = LayoutInflater.from(this).inflate(R.layout.layout_recycler_footer, rlv, false) //设置上拉刷新 rlv.addRefreshViewCreator(CommonRefreshCreator()) //添加Header rlv.addHeaderView(headerView) //添加Footer rlv.addFooterView(footerView) //添加下拉加载更多 【由于内部是通过addView实现,存在添加顺序,需要注意】 rlv.addLoadViewCreator(CommonLoadCreator()) rlv.setOnRefreshListener(object : RefreshRecyclerView.OnRefreshListener { override fun onRefresh() { rlv.postDelayed({ rlv.onStopRefresh() }, 2000) } }) rlv.setOnLoadMoreListener(object : LoadRefreshRecyclerView.OnLoadMoreListener { override fun onLoad() { rlv.postDelayed({ rlv.onStopLoad() }, 2000) } }) } }
通过自己动手实现一套下拉刷新上拉加载框架,了解了RecyclerView添加Header
以及Footer
的实现原理,通过本次学习也看到了代码剥离拆分以及设计模式运用的重要性,写代码一定要多思考,才能写出让人赏心悦目的代码。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。