編輯:關於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 —-
Android Application Thread CPU GC Operatiing and OOM Question 0603-隨手筆記
在之前app寫完測試的時候,跑完整個老化階段包括數據收發都沒問題,鍵入 adb shell top -m 5 發現我的 app pid 占用的 CPU是最多的,其實我想說
React Native 集成到已有項目
前言React Native已經出現很久了,有很多應用也在進行嘗試,前面我們也講述了怎麼創建React Native工程以及怎麼搭建原生語言與js的開發環境。但是在實際應
Android安全機制--四大組件安全
組件有Public和Private的概念,是否能被其他方調用。通過android:exported字段來確定,android:exported=true表示能,反之不行。
Android自定義Animation實現View搖擺效果
使用自定義Animation,實現View的左右搖擺效果,如圖所示:代碼很簡單,直接上源碼activity_maini.xml布局文件:<?xml vers