Android RecyclerView 上拉加載更多及下拉刷新功能的實(shí)現(xiàn)方法
RecyclerView 已經(jīng)出來很久了,但是在項(xiàng)目中之前都使用的是ListView,最近新的項(xiàng)目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,網(wǎng)上吧啦吧啦沒有合適的自己總結(jié)了一哈。
先貼圖上來看看:
使用RecyclerView實(shí)現(xiàn)上拉加載更多和下拉刷新的功能我自己有兩種方式:
1.使用系統(tǒng)自帶的Android.support.v4.widget.SwipeRefreshLayout這個(gè)控價(jià)來實(shí)現(xiàn)。
2.自定義的里面帶有RecyleView的控件。
使用RecycleView很不好添加頭部,之前在使用listview當(dāng)中自己可以添加header和bootm,但是RecycleView好像不是那么的好操作。對(duì)于第一種使用系統(tǒng)自帶的Android.support.v4.widget.SwipeRefreshLayout來實(shí)現(xiàn)的,也很好用,但是產(chǎn)品一般不要這種下拉刷新,為了讓自己顯得牛逼,他一般會(huì)搞一個(gè)自己的帶有動(dòng)畫,這就比較扯淡了。。。所以就只能用方法2了。
大致說一哈方法2的實(shí)現(xiàn)方式,父布局為ViewGroup,里面添加View第一個(gè)為控件為header第二個(gè)控件為RecycleView,至于最底部的下拉加載更多試圖,通過RecycleViw的Adapter來添加。
有了思路就搞起來:
package com.krain.srecyclerview.fruitview; import android.content.Context; import android.graphics.drawable.AnimationDrawable; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import com.krain.srecyclerview.R; /** * Created by dafuShao on 2016/9/9 0009. * */ public class ElizabethView extends FrameLayout { private ImageView imageView; private AnimationDrawable animationDrawable; public ElizabethView(Context context) { super(context); initview(context); } public ElizabethView(Context context, AttributeSet attrs) { super(context, attrs); initview(context); } public ElizabethView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initview(context); } private void initview(Context context){ View view= LayoutInflater.from(context).inflate(R.layout.elizabeth_item,null); imageView=(ImageView) view.findViewById(R.id.elizabeth_im); animationDrawable= (AnimationDrawable) imageView.getBackground(); addView(view); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } //開始動(dòng)畫 public void startAnim(){ animationDrawable.start(); } //停止動(dòng)畫 public void stopAnim(){ animationDrawable.stop(); } }
這是頭部控價(jià)很簡單里面有一個(gè)小的臭蛋眼睛左右擠一哈的效果就不貼圖了。
下面是自定義的包含RecyclerView的控件代碼如下:
package com.krain.srecyclerview.srecyclerview; import android.content.Context; import android.os.Handler; import android.os.Message; import android.support.v4.view.MotionEventCompat; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.Scroller; import android.widget.TextView; import com.krain.srecyclerview.R; import com.krain.srecyclerview.fruitview.ElizabethView; public class SRecyclerView extends ViewGroup { Context context; RecyclerView mRecyclerView; ElizabethView mHeaderView; TextView mFootViewTips;//footview的文字顯示 AdapterWrapper mAdapter; boolean mIsTop = true;//是否滑動(dòng)到了最頂部 RecyclerView.LayoutManager mLayoutManager; int mLastVisibleItem; int mFirstVisibleItem; OnRecyclerStatusChangeListener mRecyclerChangeListener; int mStatus;//當(dāng)前狀態(tài) int mHeadviewHeight;//headview的高度 Scroller mScroller; int mFristScollerY;//最開始的getscrolly boolean mHasFooter;//是否有上拉加載的功能 boolean mShowFootVisible;//是否顯示FOOTERview在mHasFooter為true的時(shí)候生效 boolean mHasRefresh = true;//是否支持下拉刷新 private final int DEFAULT_MIN_PAGEINDEX = 1;//默認(rèn)最小的頁數(shù) int mMaxPage = DEFAULT_MIN_PAGEINDEX;//分頁的總頁數(shù) int mCurrentPage = DEFAULT_MIN_PAGEINDEX;//當(dāng)前的頁數(shù),從1開始 private final int STATUS_NORMAL = 0, STATUS_REFRESH = 1, STATUS_LOAD = 2; private final int MSG_LOAD_COMPLETE = 1, MSG_REFRESH_COMPLETE = 0;//handle的常量 private final int DELAY_LOAD_COMPLETE = 1000, DELAY_REFRESH_COMPLETE = 1000;//加載完成延時(shí)回收的時(shí)間 public SRecyclerView(Context context) { super(context); init(context); } public SRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public SRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } /** * 設(shè)置最大頁數(shù) * * @param maxPage */ public void setMaxPage(int maxPage) { this.mMaxPage = maxPage; } /** * 是否支持上拉加載 * * @param hasLoadmore */ public void setLoadmore(boolean hasLoadmore) { mHasFooter = hasLoadmore; } public void setRecyclerViewLayoutManage(RecyclerView.LayoutManager mLayoutManage){ this.mLayoutManager=mLayoutManage; } /** * 關(guān)閉下拉刷新功能 */ public void disableRefresh() { mHasRefresh = false; } public void setAdapter(BaseRecyclerViewAdapter adapter) { int height = 0; if (mMaxPage == DEFAULT_MIN_PAGEINDEX) { mHasFooter = false; } mAdapter = new AdapterWrapper(context, adapter); mRecyclerView.setAdapter(mAdapter); } private int getViewHeight(View view) { int measure = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); view.measure(measure, measure); return view.getMeasuredHeight(); } /** * 獲取viewgroup里面的recyclerview * * @return */ public RecyclerView getRecyclerView() { return mRecyclerView; } public void setOnRecyclerChangeListener(OnRecyclerStatusChangeListener listener) { mRecyclerChangeListener = listener; } /** * 設(shè)置RecyclerView添加、刪除Item的動(dòng)畫 * * @param animator */ public void setItemAnimator(RecyclerView.ItemAnimator animator) { mRecyclerView.setItemAnimator(animator); } public void notifyDataSetChanged() { mStatus = STATUS_NORMAL;//重新set數(shù)據(jù)代表loadmore結(jié)束了,此時(shí)恢復(fù)成普通狀態(tài) mAdapter.notifyDataSetChanged(); } public void notifyDataInsert(int positionStart, int itemCount) { mStatus = STATUS_NORMAL;//重新set數(shù)據(jù)代表loadmore結(jié)束了,此時(shí)恢復(fù)成普通狀態(tài) mAdapter.notifyItemRangeInserted(positionStart, itemCount); } public void notifyDataRemove(int position) { mStatus = STATUS_NORMAL;//重新set數(shù)據(jù)代表loadmore結(jié)束了,此時(shí)恢復(fù)成普通狀態(tài) mAdapter.notifyItemRemoved(position); } /** * 初始化操作 * * @param context */ void init(Context context) { this.context = context; mScroller = new Scroller(context); // if (mLayoutManager!=null){ // addChildView(context,mLayoutManager); // }else{ // addChildView(context, new LinearLayoutManager(context)); // } addChildView(context); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } /** * 增加子View * * @param context */ void addChildView(Context context, RecyclerView.LayoutManager mLayoutManager) { ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); mHeaderView = new ElizabethView(context); mRecyclerView = new RecyclerView(context); addView(mHeaderView); addView(mRecyclerView); //mLayoutManager = new LinearLayoutManager(context); // mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(mLayoutManager); // 設(shè)置Item增加、移除默認(rèn)動(dòng)畫 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.addOnScrollListener(onScrollListener); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutParams(params); } void addChildView(Context contex) { ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); mHeaderView = new ElizabethView(context); mRecyclerView = new RecyclerView(context); addView(mHeaderView); addView(mRecyclerView); //mLayoutManager = new LinearLayoutManager(context); mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(mLayoutManager); // 設(shè)置Item增加、移除默認(rèn)動(dòng)畫 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.addOnScrollListener(onScrollListener); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutParams(params); } /** * 屏蔽Recyclerview的觸摸事件(下拉刷新的時(shí)候) */ float lastY; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); switch (action) { case MotionEvent.ACTION_DOWN: lastY = ev.getRawY(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: return false; case MotionEvent.ACTION_MOVE: if (mHasRefresh && mIsTop && ev.getRawY() > lastY) return true; break; } return false; } float offsetY = 0; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_MOVE: offsetY = Math.abs(event.getRawY() - lastY); //Y差值絕對(duì)值 if (offsetY > 0) scrollToOffset(offsetY); else { mIsTop = false; } break; case MotionEvent.ACTION_UP: if (getScrollY() <= 0) { doRefresh(); mHeaderView.stopAnim(); mHeaderView.startAnim(); } else complete(); break; } return super.onTouchEvent(event); } /** * 滾動(dòng)這個(gè)view到手滑動(dòng)的位置 * * @param offsetY Y軸偏移量 */ void scrollToOffset(float offsetY) { //假如正在刷新并且現(xiàn)在的scrolly和初始值一樣的時(shí)候,代表準(zhǔn)備下拉開始刷新,并執(zhí)行一次only if (getScrollY() == mFristScollerY && mRecyclerChangeListener != null) mRecyclerChangeListener.startRefresh(); int value = Math.round(offsetY / 2.0F); value = mFristScollerY - value; scrollTo(0, value); } /** * 執(zhí)行刷新操作,移動(dòng)到header剛出來的位置 */ void doRefresh() { mStatus = STATUS_REFRESH; int currentY = getScrollY(); mScroller.startScroll(0, currentY, 0, (mFristScollerY - mHeadviewHeight) - currentY); invalidate(); if (mRecyclerChangeListener != null) mRecyclerChangeListener.onRefresh(); handler.sendEmptyMessageDelayed(MSG_REFRESH_COMPLETE, DELAY_REFRESH_COMPLETE); } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == MSG_LOAD_COMPLETE) { View footview = mAdapter.getFootView(); if (footview != null) mRecyclerView.smoothScrollBy(0, -footview.getMeasuredHeight()); } else if (msg.what == MSG_REFRESH_COMPLETE) complete(); } }; /** * header返回原處完全隱藏 */ public void complete() { mCurrentPage = DEFAULT_MIN_PAGEINDEX;//完成之后當(dāng)前的page恢復(fù)默認(rèn)值 if (mFootViewTips != null) mFootViewTips.setText(context.getString(R.string.loading));//更改foot提示為正在加載中 if (mRecyclerChangeListener != null) mRecyclerChangeListener.refreshComplete(); mStatus = STATUS_NORMAL; int currentY = getScrollY(); mScroller.startScroll(0, currentY, 0, mFristScollerY - currentY); mHeaderView.stopAnim(); invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); height += child.getMeasuredHeight(); } setMeasuredDimension(width, height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = getPaddingLeft(); int top = getPaddingTop(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (i == 0) {//當(dāng)是header的時(shí)候居中顯示 int headerLeft = getMeasuredWidth() / 2 - child.getMeasuredWidth() / 2; child.layout(headerLeft, top, headerLeft + child.getMeasuredWidth(), top + child.getMeasuredHeight()); } else child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); top += child.getMeasuredHeight(); } mHeadviewHeight = getPaddingTop() + mHeaderView.getMeasuredHeight(); scrollTo(0, mHeadviewHeight);//移動(dòng)到header下方以顯示recyleview mFristScollerY = getScrollY(); } /** * RecyclerView的滑動(dòng)監(jiān)聽事件 */ RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { //滑動(dòng)到了頂部 if (mFirstVisibleItem == 0) { mIsTop = true; } else { mIsTop = false; if (mStatus != STATUS_LOAD && mShowFootVisible && mLastVisibleItem + 1 == mAdapter.getItemCount()) { if (mCurrentPage == mMaxPage) { //當(dāng)前頁面是最后一頁的時(shí)候 mFootViewTips = (TextView) mAdapter.getFootView().findViewById(R.id.footer_tips); mFootViewTips.setText(context.getString(R.string.last_page_tips)); handler.sendEmptyMessageDelayed(MSG_LOAD_COMPLETE, DELAY_LOAD_COMPLETE); } else { mStatus = STATUS_LOAD; if (mRecyclerChangeListener != null) { mRecyclerChangeListener.onLoadMore(); mCurrentPage++; } } } } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (mLayoutManager instanceof LinearLayoutManager) { mLastVisibleItem = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition(); mFirstVisibleItem = ((LinearLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition(); setFootviewVisible(); } else if (mLayoutManager instanceof GridLayoutManager) { mLastVisibleItem = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition(); mFirstVisibleItem = ((GridLayoutManager) mLayoutManager).findFirstCompletelyVisibleItemPosition(); setFootviewVisible(); } else if (mLayoutManager instanceof StaggeredGridLayoutManager) { //因?yàn)镾taggeredGridLayoutManager的特殊性可能導(dǎo)致最后顯示的item存在多個(gè),所以這里取到的是一個(gè)數(shù)組 //得到這個(gè)數(shù)組后再取到數(shù)組中position值最大的那個(gè)就是最后顯示的position值了 int[] lastPositions = new int[((StaggeredGridLayoutManager) mLayoutManager).getSpanCount()]; ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(lastPositions); mLastVisibleItem = findMax(lastPositions); mFirstVisibleItem = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(lastPositions)[0]; setFootviewVisible(); } } }; void setFootviewVisible() { //當(dāng)設(shè)置了擁有上拉加載功能但是第一頁的條目不足以盛滿Recyclerview的時(shí)候隱藏footer if (mHasFooter && mFirstVisibleItem == 0) { /** * 這里加上一個(gè)mShowFootVisible在上拉加載功能啟用的情況下生效,從來控制item數(shù)量不足鋪滿 * recyclerview高度的時(shí)刻隱藏footview,在item數(shù)量超過view高度的情況下顯示 */ if (mLastVisibleItem + 1 == mAdapter.getItemCount()) { mShowFootVisible = false; } else mShowFootVisible = true; notifyDataSetChanged(); } } private int findMax(int[] positions) { int max = positions[0]; for (int value : positions) { if (value > max) { max = value; } } return max; } private class AdapterWrapper extends RecyclerView.Adapter { private static final int TYPE_ITEM = 0; private static final int TYPE_FOOTER = 1; private RecyclerView.Adapter mAdapter; private Context mContext; View footer; public AdapterWrapper(Context context, RecyclerView.Adapter wrappedAdapter) { this.mContext = context; this.mAdapter = wrappedAdapter; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { RecyclerView.ViewHolder holder = null; switch (viewType) { case TYPE_ITEM: holder = mAdapter.onCreateViewHolder(parent, viewType); break; case TYPE_FOOTER: footer = LayoutInflater.from(mContext).inflate(R.layout.lib_recyle_footview, null); LinearLayout linearLayout= (LinearLayout) footer.findViewById(R.id.loading_layout); StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.setFullSpan(true); linearLayout.setLayoutParams(layoutParams); holder = new FooterViewHolder(footer); break; } return holder; } public View getFootView() { return footer; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (!mHasFooter || position + 1 != getItemCount()) { mAdapter.onBindViewHolder(holder, position); } } @Override public int getItemCount() { return mShowFootVisible ? mAdapter.getItemCount() + 1 : mAdapter.getItemCount(); } @Override public int getItemViewType(int position) { if (mShowFootVisible && position + 1 == getItemCount()) { return TYPE_FOOTER; } else { return TYPE_ITEM; } } private class FooterViewHolder extends RecyclerView.ViewHolder { public ProgressBar progressBar; public TextView tvLoading; public LinearLayout llyLoading; public FooterViewHolder(View itemView) { super(itemView); progressBar = (ProgressBar) itemView.findViewById(R.id.progress_loading); tvLoading = (TextView) itemView.findViewById(R.id.footer_tips); llyLoading = (LinearLayout) itemView.findViewById(R.id.loading_layout); } } } }
最后還有一個(gè)就是Adapter的代碼:
package com.krain.srecyclerview.srecyclerview; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; public abstract class BaseRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { private OnItemClickLisener mItemListener; @Override public VH onCreateViewHolder(ViewGroup parent, int viewType) { View view = getItemView(viewType, parent); VH vh = getViewHolder(view); view.setOnClickListener(new OnRecyclerAdapterclickListener(vh, viewType)); view.setOnLongClickListener(new OnRecyclerAdapterclickListener(vh, viewType)); return vh; } public abstract VH getViewHolder(View itemView); /** * 返回item的view * * @return */ public abstract View getItemView(int viewType, ViewGroup parent); /** * 返回Adapter每個(gè)itemn的數(shù)據(jù) 可選 */ public Object getItem(int position) { return null; } /** * item點(diǎn)擊事件接口 * * @param mItemListener */ public void setOnItemListener(OnItemClickLisener mItemListener) { this.mItemListener = mItemListener; } @Override public abstract void onBindViewHolder(VH holder, int position); @Override public abstract int getItemCount(); class OnRecyclerAdapterclickListener implements View.OnClickListener, View.OnLongClickListener { VH viewholder; int viewType; public OnRecyclerAdapterclickListener(VH viewholder, int viewType) { this.viewholder = viewholder; this.viewType = viewType; } @Override public void onClick(View v) { if (mItemListener != null && viewholder.getAdapterPosition() != RecyclerView.NO_POSITION) { mItemListener.onItemClick(viewholder.getAdapterPosition(), viewType, viewholder, v); } } @Override public boolean onLongClick(View v) { if (mItemListener != null && viewholder.getAdapterPosition() != RecyclerView.NO_POSITION) { mItemListener.onItemLongClick(viewholder.getAdapterPosition(), viewType, viewholder, v); } return false; } } }
需要注意一哈:
如果想改變Reciview的布局方式在這個(gè)修改
void addChildView(Context contex) { ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); mHeaderView = new ElizabethView(context); mRecyclerView = new RecyclerView(context); addView(mHeaderView); addView(mRecyclerView); //mLayoutManager = new LinearLayoutManager(context); mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(mLayoutManager); // 設(shè)置Item增加、移除默認(rèn)動(dòng)畫 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.addOnScrollListener(onScrollListener); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutParams(params); }
mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);這一行就是了改成對(duì)應(yīng)的就可以了,這兒沒有封裝過幾天封裝一個(gè)出來。
還需要注意一哈就是在滑動(dòng)判斷是不是最后一行,如果是瀑布流就要注意哈判斷的方式和其他的不一樣,
if (mLayoutManager instanceof StaggeredGridLayoutManager) { //因?yàn)镾taggeredGridLayoutManager的特殊性可能導(dǎo)致最后顯示的item存在多個(gè),所以這里取到的是一個(gè)數(shù)組 //得到這個(gè)數(shù)組后再取到數(shù)組中position值最大的那個(gè)就是最后顯示的position值了 int[] lastPositions = new int[((StaggeredGridLayoutManager) mLayoutManager).getSpanCount()]; ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(lastPositions); mLastVisibleItem = findMax(lastPositions); mFirstVisibleItem = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(lastPositions)[0]; setFootviewVisible(); }
因?yàn)镾taggeredGridLayoutManager的特殊性可能導(dǎo)致最后顯示的item存在多個(gè),所以這里取到的是一個(gè)數(shù)組,得到這個(gè)數(shù)組后再取到數(shù)組中position值最大的那個(gè)就是最后顯示的position值了再去設(shè)置最后一行加載更多的顯示。
以上所述是小編給大家介紹的Android RecyclerView 上拉加載更多及下拉刷新功能的實(shí)現(xiàn)方法,希望對(duì)大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的,在此也非常感謝大家對(duì)腳本之家網(wǎng)址的支持!
- Android中使用RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載
- Android RecyclerView實(shí)現(xiàn)下拉刷新和上拉加載
- 詳解Recyclerview item中有EditText使用刷新遇到的坑
- Android使用recyclerview打造真正的下拉刷新上拉加載效果
- android RecyclerView側(cè)滑菜單,滑動(dòng)刪除,長按拖拽,下拉刷新上拉加載
- XRecyclerView實(shí)現(xiàn)下拉刷新、滾動(dòng)到底部加載更多等功能
- Android使用RecyclerView實(shí)現(xiàn)自定義列表、點(diǎn)擊事件以及下拉刷新
- Android RecyclerView的刷新分頁的實(shí)現(xiàn)
- Android RecyclerView下拉刷新和上拉加載更多
- RecyclerView使用payload實(shí)現(xiàn)局部刷新
相關(guān)文章
Android利用POI實(shí)現(xiàn)將圖片插入到Excel
這篇文章主要為大家詳細(xì)介紹了Android如何利用POI實(shí)現(xiàn)將圖片插入到Excel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11彈出一個(gè)帶確認(rèn)和取消的dialog實(shí)例
下面小編就為大家?guī)硪黄獜棾鲆粋€(gè)帶確認(rèn)和取消的dialog實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03Android實(shí)現(xiàn)文件上傳和下載倒計(jì)時(shí)功能的圓形進(jìn)度條
這篇文章主要介紹了Android實(shí)現(xiàn)文件上傳和下載倒計(jì)時(shí)功能的圓形進(jìn)度條,需要的朋友可以參考下2017-09-09Android DownloadMananger管理器實(shí)現(xiàn)下載圖片功能
Android DownloadMananger類似于下載隊(duì)列,管理所有當(dāng)前正在下載或者等待下載的項(xiàng)目,他可以維持HTTP鏈接,并且在隊(duì)列中的下載項(xiàng)目一旦失敗,還能自動(dòng)重新下載2023-01-01Android開發(fā)之圓角矩形創(chuàng)建工具RoundRect類定義與用法分析
這篇文章主要介紹了Android開發(fā)之圓角矩形創(chuàng)建工具RoundRect類定義與用法,結(jié)合完整實(shí)例形式分析了Android圓角矩形工具類的定義與簡單使用技巧,需要的朋友可以參考下2018-01-01android TextView多行文本(超過3行)使用ellipsize屬性無效問題的解決方法
這篇文章介紹了android TextView多行文本(超過3行)使用ellipsize屬性無效問題的解決方法,有需要的朋友可以參考一下2013-09-09Android FTP 多線程斷點(diǎn)續(xù)傳下載\上傳的實(shí)例
本篇文章主要介紹了Android FTP 多線程斷點(diǎn)續(xù)傳下載\上傳的實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08