English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
RecyclerView는 오랫동안 존재해 왔지만, 프로젝트에서는 ListView를 사용했었고, 최근 새로운 프로젝트에서는 많이 사용하고 있습니다. 특히, 스타일의 내려다보기 새로고침은 인터넷에서 적절한 것이 없어, 나는 자신만의 요약을 만들었습니다.
그림을 붙여보겠습니다:
RecyclerView를 사용하여 상단 로드 및 하단 새로고침 기능을 구현하는 방법은 두 가지가 있습니다:
1의 Android.support.v4의 SwipeRefreshLayout를 통해 구현됩니다.
2의 컨트롤에 RecyleView를 포함한 컨트롤을 추가합니다.
RecycleView를 사용하여 헤더를 추가하는 것이 매우 어렵습니다. 이전에는 ListView를 사용할 때 헤더와 바텀을 추가할 수 있었지만, RecycleView는 그렇게 잘 작동하지 않습니다. 첫 번째 방법은 시스템이 제공하는 Android.support.v4.widget.SwipeRefreshLayout를 통해 구현되며, 매우 유용하지만, 제품은 일반적으로 이러한 내려다보기 새로고침을 사용하지 않습니다. 자신을 더 나은 것으로 보이기 위해, 그는 일반적으로 애니메이션을 포함한 자신만의 새로고침을 만들어야 하며, 이는 매우 무의미합니다. 따라서, 방법을 사용해야 합니다.2이렇게 합니다.
기본적으로 방법을 설명해 보겠습니다:2구현 방식은 ViewGroup가 부모 레이아웃이며, View를 추가하여 첫 번째 컨트롤이 헤더이고 두 번째 컨트롤이 RecycleView입니다. 가장 아래의 더 많은 내려다보기 뷰는 RecycleView의 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; /** * dafuShao에 의해 만들어진 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); } //애니메이션 시작 public void startAnim(){ animationDrawable.start(); } //애니메이션 중지 public void stopAnim(){ animationDrawable.stop(); } }
헤더 컨트롤은 매우 간단합니다. 작은 냄새가 나는 눈이 왼쪽과 오른쪽으로 약간 누르면 됩니다. 그래서 그림을 붙이지 않았습니다.
다음은 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;//최상단으로 스크롤됐는지 확인 RecyclerView.LayoutManager mLayoutManager; int mLastVisibleItem; int mFirstVisibleItem; OnRecyclerStatusChangeListener mRecyclerChangeListener; int mStatus;//현재 상태 int mHeadviewHeight;//headview의 높이 Scroller mScroller; int mFristScollerY;//최초의 getscrolly boolean mHasFooter;//상승 로드 기능이 있는지 여부 boolean mShowFootVisible;//mHasFooter가 true일 때 FOOTERview를 표시할지 여부 boolean mHasRefresh = true;//스크롤을 지원하는지 여부 private final int DEFAULT_MIN_PAGEINDEX = 1;//기본적인 가장 작은 페이지 수 int mMaxPage = DEFAULT_MIN_PAGEINDEX;//페이지링크의 총 페이지 수 int mCurrentPage = DEFAULT_MIN_PAGEINDEX;//현재 페이지 수,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;//로드가 완료된 후에延时回收的时间 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); } /** * 최대 페이지 수 설정 * * @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; } /** * 下拉 새로고침 기능을关闭합니다 */ 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; } /** * RecyclerView 추가, 제거 Item의 애니메이션을 설정합니다 * * @param animator */ public void setItemAnimator(RecyclerView.ItemAnimator animator) { mRecyclerView.setItemAnimator(animator); } public void notifyDataSetChanged() { mStatus = STATUS_NORMAL;//重新set数据代表loadmore结束了,此时恢复成普通状态 mAdapter.notifyDataSetChanged(); } public void notifyDataInsert(int positionStart, int itemCount) { mStatus = STATUS_NORMAL;//重新set数据代表loadmore结束了,此时恢复成普通状态 mAdapter.notifyItemRangeInserted(positionStart, itemCount); } public void notifyDataRemove(int position) { mStatus = STATUS_NORMAL;//重新set数据代表loadmore结束了,此时恢复成普通状态 mAdapter.notifyItemRemoved(position); } /** * 初始化操作 * * @param context */ void init(Context context) { this.context = context; mScroller = new Scroller(context); // if (mLayoutManager!=null){ // addChildView(context,mLayoutManager); // } // 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); // Item 추가, 제거 기본 애니메이션 설정 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); // Item 추가, 제거 기본 애니메이션 설정 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.addOnScrollListener(onScrollListener); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutParams(params); } /** * 屏蔽Recyclerview的触摸事件(下拉刷新的时候) */ 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 차이의 절대값 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); } /** * 이 뷰를 손으로 드래그한 위치로 스크롤 * * @param offsetY Y축 이동량 */ void scrollToOffset(float offsetY) { //현재 새로고침 중이고 현재의 scrolly와 초기 값이 같을 때, 준비하여下拉 새로고침을 시작하고 only를 한 번 실행 if (getScrollY() == mFristScollerY && mRecyclerChangeListener != null) mRecyclerChangeListener.startRefresh(); int value = Math.round(offsetY / 2.0F); value = mFristScollerY - value; scrollTo(0, value); } /** * 수정 작업 수행, 헤더가 최초로 나타난 위치로 이동 */ 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(); } }; /** * 헤더가 원래 위치로 돌아가 전체적으로 숨기기 */ public void complete() { mCurrentPage = DEFAULT_MIN_PAGEINDEX;//작업이 완료된 후 현재 페이지가 기본 값으로 복구 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) {//헤더가 되었을 때 중앙에 표시하려면 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);//헤더 아래로 이동하여 recyleview를 표시하려면 mFristScollerY = getScrollY(); } /** * RecyclerView의 스크롤 리스너 이벤트 */ RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == RecyclerView.SCROLL_STATE_IDLE) { //끝으로 스크롤되었습니다 if (mFirstVisibleItem == 0) { mIsTop = true; } else { mIsTop = false; if (mStatus != STATUS_LOAD && mShowFootVisible && mLastVisibleItem + 1 == mAdapter.getItemCount()) { if (mCurrentPage == mMaxPage) { //현재 페이지가 마지막 페이지일 때 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) { //StaggeredGridLayoutManager의 특성상 마지막으로 표시된 item이 여러 개 있을 수 있으므로, 여기서 얻는 것은 배열입니다 //이 배열을 얻은 후, 배열에서 position 값이 가장 큰 것이 마지막으로 표시된 position 값입니다 int[] lastPositions = new int[((StaggeredGridLayoutManager) mLayoutManager).getSpanCount()]; ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(lastPositions); mLastVisibleItem = findMax(lastPositions); mFirstVisibleItem = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(lastPositions)[0]; setFootviewVisible(); } } }; void setFootviewVisible() { //Pull-to-refresh 기능이 설정되었지만 첫 페이지의 항목이 Recyclerview를 채우지 못할 때 footer를 숨기기 if (mHasFooter && mFirstVisibleItem == 0) { /** * 여기에 mShowFootVisible를 추가하여 pull-to-refresh 기능이 활성화된 경우 item 수가 부족하여 view를 채우지 못하는 경우 제어 * recyclerview의 높이가 현재 view 높이보다 큰 경우 footview를 숨기고, item 수가 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); } } } }
마지막으로 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 각 item의 데이터를 반환합니다. 선택 사항 */ public Object getItem(int position) { return null; } /** * item 클릭 이벤트 인터페이스 * * @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的布局方式在这个修改
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); // Item 추가, 제거 기본 애니메이션 설정 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.addOnScrollListener(onScrollListener); mRecyclerView.setHasFixedSize(true); mRecyclerView.setLayoutParams(params); }
mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); 이 줄이 바로입니다. 대응하는 것으로 변경하면 됩니다. 여기서는 포장되지 않았고, 몇 일 후 포장할 예정입니다.
또한 주의해야 할 것은, 스크롤할 때 마지막 행인지 확인하는 것입니다.瀑布형이면 다른 방식과 달리 확인해야 합니다.
if (mLayoutManager instanceof StaggeredGridLayoutManager) { //StaggeredGridLayoutManager의 특성상 마지막으로 표시된 item이 여러 개 있을 수 있으므로, 여기서 얻는 것은 배열입니다 //이 배열을 얻은 후, 배열에서 position 값이 가장 큰 것이 마지막으로 표시된 position 값입니다 int[] lastPositions = new int[((StaggeredGridLayoutManager) mLayoutManager).getSpanCount()]; ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(lastPositions); mLastVisibleItem = findMax(lastPositions); mFirstVisibleItem = ((StaggeredGridLayoutManager) mLayoutManager).findFirstVisibleItemPositions(lastPositions)[0]; setFootviewVisible(); }
StaggeredGridLayoutManager의 특성상 마지막으로 표시된 item이 여러 개 있을 수 있으므로, 여기서는 배열을 가져오고, 이 배열에서 position 값이 가장 큰 것을 가져와 마지막으로 표시된 position 값으로 설정합니다. 그런 다음, 마지막 행에 더 많은 데이터를 로드하는 표시를 설정합니다.
위에서 설명한 것은 편집자가 여러분에게 안내한 Android RecyclerView의 상단으로 더 많은 데이터를 로드하고 하단으로 새로운 데이터를 업데이트하는 기능 구현 방법입니다. 여러분이 어떤 질문이든 가지고 계시면, 댓글을 달아 주시기 바랍니다. 편집자는 즉시 답변을 드리겠습니다. 또한,呐喊 교본 웹사이트에 대한 여러분의 지지에 깊이 감사드립니다!
언급: 이 문서의 내용은 인터넷에서 가져왔으며, 저작권자에게 속하며, 인터넷 사용자가 자발적으로 기여하고 자체적으로 업로드한 내용입니다. 이 웹사이트는 소유권을 가지지 않으며, 인공적으로 편집된 것도 아니며, 관련 법적 책임도 부담하지 않습니다. 저작권 위반이 의심되는 내용이 있으면, 메일을 notice#w로 보내 주시기 바랍니다.3codebox.com(메일을 보내면, #을 @으로 변경하여 신고하시고, 관련 증거를 제공해 주세요. 사실이 확인되면, 이 사이트는 즉시 위반된 내용을 삭제합니다.)