編輯:關於Android編程
那如同這個題目,這裡面涉及的東西其實還是比較多的,RecycleView SwipeRefreshLayout,下拉刷新(這個就是SwipeRefreshLayout的),加載更多。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMyBpZD0="swiperefreshlayout">SwipeRefreshLayout
這個是Google自己封裝的一個下拉刷新的控件,裡面使用了5.0開始的嵌套滑動機制,有興趣的朋友可以去看看源碼!使用起來其實就涉及到以下方法:
setOnRefreshListener() 下拉刷新的相關回調。
setRefresh() 通知是否開始刷新或者刷新完成。(坑1)
setColorSchemeColors() loading的時候progressbar的顏色,支持多個。
進入頁面調用setRefresh(true),更不不顯示刷新的小圓圈?!
簡單的說,這個就是在oncreate()方法執行的時候,view還沒有繪制出來,這個時候你設置刷新不刷新其實都一樣的,解決方法,post一下!
mRecyclerView.post(new Runnable() { @Override public void run() { mRefreshLayout.setRefreshing(refresh); } });
RecycleView其實出現都有一定的年頭了,前幾天公司來面試的居然說他還沒有用過。。這個也是醉醉的!
RecycleView是ListView的強力升級!加入了holder便於管理和復用相同的類型。
就我目前掌握的情況,RecycleView對於ListView有了以下的不同:
1、加入了LayoutManager用用管理各種類型的布局,而且通過不同的布局可以實現橫向、豎向、瀑布式的等各種復雜的布局。
2、加入Holder來管理相關布局和復用,對於每一種Type的View你都要創建一個對應的Holder來管理它!
3、取消了header和bottom布局。
4、沒有現成的itemClick回調。
5、引入了豐富的動畫效果。(坑4)
6、添加了豐富的數據刷新的方法,可以局部刷新了!(坑3)
7、可自定義相關分割線。
8、支持swipe刪除和drag排序。(ItemTouchHelper 幫助類)
9、默認是不顯示scrollBar的(坑2)
10、可以設置不同類型holder占據不同的空間(ItemColumnSpan)
上面這些不是所有的都講,其實本文主要涉及的就是相關adapter,裡面對應不同的holder,及相關的封裝。然後說說踩了哪些坑。
下拉刷新就調用SwipeRefreshLayout相關就好了,那麼加載更多呢?這個就要自己去寫相關的布局了。然後第一個問題,什麼時候加載更多??因為RecycleView有各種布局,所以判斷最後一個也是要區分不同的adapter的!
2、加載更多有多少種情況?1、監聽滑動,滿足條件開始加載更多。
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (null != scrollListener) { scrollListener.onScrolled(SwipeRefreshRecycleView.this, dx, dy); } if (null == manager) { throw new RuntimeException("you should call setLayoutManager() first!!"); } if (null == adapter) { throw new RuntimeException("you should call setAdapter() first!!"); } if (manager instanceof LinearLayoutManager) { int lastCompletelyVisibleItemPosition = ((LinearLayoutManager) manager).findLastCompletelyVisibleItemPosition(); if (adapter.getItemCount() > 1 && lastCompletelyVisibleItemPosition >= adapter.getItemCount() - 1 && adapter.isHasMore()) { adapter.isLoadingMore(); if (null != listener) { listener.onLoadMore(); } } int position = ((LinearLayoutManager) manager).findFirstVisibleItemPosition(); if (lastTitlePos == position) { return; } lastTitlePos = position; } if (manager instanceof StaggeredGridLayoutManager) { int[] itemPositions = new int[2]; ((StaggeredGridLayoutManager) manager).findLastVisibleItemPositions(itemPositions); int lastVisibleItemPosition = (itemPositions[1] != 0) ? ++itemPositions[1] : ++itemPositions[0]; if (lastVisibleItemPosition >= adapter.getItemCount() && adapter.isHasMore()) { adapter.isLoadingMore(); if (null != listener) { listener.onLoadMore(); } } } }
2、定義自己的加載更多的ViewHolder。
3.定義相關的方法實時更新ViewHolder的三種狀態。
public class NewBottomViewHolder extends RecyclerView.ViewHolder{ @Bind(R.id.footer_container) public LinearLayout contaier; @Bind(R.id.progressbar) ProgressBar pb; @Bind(R.id.content) TextView content; @Nullable private final SwipeRefreshRecycleView.OnRefreshLoadMoreListener mListener; public NewBottomViewHolder(View itemView, SwipeRefreshRecycleView.OnRefreshLoadMoreListener listener) { super(itemView); ButterKnife.bind(this,itemView); mListener = listener; } public void bindDateView(int state) { switch (state) { case AdapterLoader.STATE_LASTED: contaier.setVisibility(View.VISIBLE); contaier.setOnClickListener(null); pb.setVisibility(View.GONE); content.setText("--- 沒有更多了 ---"); break; case AdapterLoader.STATE_LOADING: contaier.setVisibility(View.VISIBLE); content.setText("加載更多!!"); contaier.setOnClickListener(null); pb.setVisibility(View.VISIBLE); break; case AdapterLoader.STATE_ERROR: contaier.setVisibility(View.VISIBLE); pb.setVisibility(View.GONE); content.setText("--- 加載更多失敗點擊重試 ---"); contaier.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onLoadMore(); } content.setText("加載更多!!"); pb.setVisibility(View.VISIBLE); } }); break; } } }
4.定義相關擴展方法便於用戶自己定義底部布局及相關狀態處理。
這裡就必須詳細講講Adapter裡面的相關方法了!
getItemCount(),在RecycleView知道它一共有多少數量的Item需要展示,返回0之後不會執行剩余的方法!
onCreateViewHolder(ViewGroup parent, int viewType),某種Type的Holder第一次創建的時候會調用該方法,當然沒有復用的時候也會去創建,一旦復用了,改方法不會再執行了!
onBindViewHolder(RecyclerView.ViewHolder holder, int position),每一次更新對應itemView的時候都會調用該方法,所以在該方法中要實時的刷新數據!(因為存在復用,所以刷新的時候一定要徹底!!!)
以上三個方法是必須實現的,因為在父類adapter裡是抽象滴!
還有一個方法也比較重要:
getItemViewType(int position),這個方法是返回對應pos的類型的,如果你只有一個類型,不需要重寫該方法,默認返回的是0。
是不是這麼說起來比ListView還要爽一點兒?不用去判斷什麼convertView==null!
@Override public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_BOTTOM: if (loadMore != null) { RecyclerView.ViewHolder holder = onBottomViewHolderCreate(loadMore); if (holder == null) { throw new RuntimeException("You must impl onBottomViewHolderCreate() and return your own holder "); } return holder; } else { return new BottomViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_footer, parent, false)); } default: return onViewHolderCreate(parent, viewType); } } @Override public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (getItemViewType(position) == TYPE_BOTTOM) { loadState = loadState == STATE_ERROR ? STATE_ERROR : isHasMore() ? STATE_LOADING : STATE_LASTED; if (loadMore != null) { try { onBottomViewHolderBind(holder, loadState); } catch (Exception e) { e.printStackTrace(); } } else { try { ((BottomViewHolder) holder).bindDateView(loadState); } catch (Exception e) { e.printStackTrace(); } } } else { onViewHolderBind(holder, position); } }
這裡在RefreshRecycleAdapter
RecyclerView.ViewHolder onViewHolderCreate(ViewGroup parent, int viewType); void onViewHolderBind(RecyclerView.ViewHolder holder, int position);
對於加載更多的幾種狀態的更改,提供如下的相關方法!
boolean isHasMore(); void isLoadingMore(); void loadMoreError();
對於創建自己制定的加載更多的布局,提供如下方法擴展!
void setLoadMoreView(View view); RecyclerView.ViewHolder onBottomViewHolderCreate(View loadMore); void onBottomViewHolderBind(RecyclerView.ViewHolder holder, int loadState);
還沒有說的那就是數據源相關的方法。提供了set和append兩種方式!
void setList(Listdata); void appendList(List data); @Override public final void appendList(List data) { int positionStart = list.size(); list.addAll(data); int itemCount = list.size() - positionStart; if (positionStart == 0) { notifyDataSetChanged(); } else { notifyItemRangeInserted(positionStart + 1, itemCount); } }
還是那話,這些方法都是RefreshRecycleAdapter
說到這裡不得不提提RecycleView刷新數據的相關方法和坑!
在notifyDataSetChanged()的基礎上, RecycleView增加了一系列的方法用於增刪改。。
notifyItemInserted(); notifyItemRangeInserted(); notifyItemChanged(); notifyItemRangeChanged(); notifyItemRemoved(); notifyItemRangeRemoved();
在使用的過程中,發現調用notifyItemChanged()之後不會去執行onBindViewHolder(),(坑3 坑4)這個就導致刷新沒有觸發了!最後搜到的結果是因為mRecyclerView.setItemAnimator(new DefaultItemAnimator())引起的,解決方案是復寫相關方法
@Override public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List
首先通過addList()或者appendList()的方法設置相關數據源。
滑動過程中需要加載更多時回調相關方法,並在adapter中通知相關狀態刷新。
adapter.isLoadingMore(); if (null != listener) { listener.onLoadMore(); }
加載錯誤的時候調用相關的方法通知狀態改變。
adapter.loadMoreError();
創建BottomHolder的時候判斷有沒有設置自定義的view,如果有,那麼就去走子類的onBottomViewHolderCreate()方法創建自定義的Bottomholder,然後實時更新相關數據!
@Override public final void setLoadMoreView(@NonNull View view) { loadMore = view; } if (loadMore != null) { RecyclerView.ViewHolder holder = onBottomViewHolderCreate(loadMore); if (holder == null) { throw new RuntimeException("You must impl onBottomViewHolderCreate() and return your own holder "); } return holder; }
最後在onBottomViewHolderBind(RecyclerView.ViewHolder holder, int state)的方法中執行bindDateView(state)實時刷新相關的狀態。
public void bindDateView(int state) { switch (state) { case AdapterLoader.STATE_LASTED: contaier.setVisibility(View.VISIBLE); contaier.setOnClickListener(null); pb.setVisibility(View.GONE); content.setText("--- 沒有更多了 ---"); break; case AdapterLoader.STATE_LOADING: contaier.setVisibility(View.VISIBLE); content.setText("加載更多!!"); contaier.setOnClickListener(null); pb.setVisibility(View.VISIBLE); break; case AdapterLoader.STATE_ERROR: contaier.setVisibility(View.VISIBLE); pb.setVisibility(View.GONE); content.setText("--- 加載更多失敗點擊重試 ---"); contaier.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mListener != null) { mListener.onLoadMore(); } content.setText("加載更多!!"); pb.setVisibility(View.VISIBLE); } }); break; } }
PS 最後還有默認是不顯示scrollBar的問題,這個問題,似乎必須在xml裡面配置,不能代碼直接new RecycleView。然後可以使用相關代碼控制ScrollBar是否顯示!
mRecyclerView.setVerticalScrollBarEnabled(true)
另外對於特性8、10這裡就不詳細介紹了,滑動刪除和拖拽排序在TouchHelperCallback中有相關支持!方法如下:
@Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { if (callBack != null) { callBack.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); } return true; } @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { if (callBack != null) { callBack.onItemDismiss(viewHolder.getAdapterPosition()); } }
詳細的可以參照相關Demo-FangShiActivity
compile 'com.lovejjfg.powerrecycle:powerrecycle:1.0.0'
演示Demo下載
項目中的使用
—- Edit By Joe —-
在之前app寫完測試的時候,跑完整個老化階段包括數據收發都沒問題,鍵入 adb shell top -m 5 發現我的 app pid 占用的 CPU是最多的,其實我想說
前言React Native已經出現很久了,有很多應用也在進行嘗試,前面我們也講述了怎麼創建React Native工程以及怎麼搭建原生語言與js的開發環境。但是在實際應
組件有Public和Private的概念,是否能被其他方調用。通過android:exported字段來確定,android:exported=true表示能,反之不行。
使用自定義Animation,實現View的左右搖擺效果,如圖所示:代碼很簡單,直接上源碼activity_maini.xml布局文件:<?xml vers