為什麼要使用RecycleView,而不再使用ListView
記得每一次在用ListView的時候,在Adapter中,總是需要我們自己去建立一個ViewHolder,去存儲ListItem的布局,這麼做的原因在于findViewById()是一個很耗時間的操作,是以我們需要一個靜态的對象将layout過的控件給儲存起來,下一次重新整理這個item的時候,就不再需要調用findViewById去ViewTree中初始化控制,進而達到對ListView的優化效果。
而RecycleView則已經幫我們封閉好了這樣一個ViewHolder的抽象類RecycleView.ViewHolder,而且是必須實作的一個接口,這說明在控制節省記憶體方面,RecycleView要比ListView做得要好,因為在ListView中,你不寫ViewHolder也是可以的。
此外,ListView的設計是一個上下滑動的清單控制,而RecycleView則通過一個LayoutManager來實作多種布局的展現,包括縱向清單,橫向Gallery,Grid布局,基于瀑布流等,可以說,之前通過ListView, GridView, ViewPager等實作的布局,現在用一個RecycleView就可以實作了。
再此外,現在的很多app,就算是使用ListView,也不僅僅是單純地展現資料,都希望能夠利用一些平滑的動畫效果來提升使用者體驗,而RecycleView本身在對資料的增删上就添加了對動畫的效果的的支援。
在RecyclerView中增加了以下的接口:
public final void notifyItemInserted(int position) {
mObservable.notifyItemRangeInserted(position, );
}
public final void notifyItemMoved(int fromPosition, int toPosition) {
mObservable.notifyItemMoved(fromPosition, toPosition);
}
public void setItemAnimator(ItemAnimator animator) {
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
mItemAnimator.setListener(null);
}
mItemAnimator = animator;
if (mItemAnimator != null) {
mItemAnimator.setListener(mItemAnimatorListener);
}
}
綜合種種,個人覺得,是很有必要掌握一下如何使用RecycleView的。
如何使用 RecycleView
RecycleView是Support-v7包中的元件,是以在Gradle中,我們要添加其對應的引用
dependencies {
...
compile 'com.android.support:recyclerview-v7:23.1.0'
...
}
在xml布局中,如下使用
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_widget"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/order_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/normal_space" />
</android.support.v4.widget.SwipeRefreshLayout>
在Activity中,
private RecyclerView mOrderListView;
private LinearLayoutManager mLayoutManager;
private OrderListRecycleViewAdapter mOrderListAdapter;
mOrderListView = (RecyclerView) findViewById(R.id.order_list);
mLayoutManager = new LinearLayoutManager(this);
mOrderListView.setHasFixedSize(true);
mOrderListView.setLayoutManager(mLayoutManager);
mOrderListAdapter = new OrderListRecycleViewAdapter(this, mOrderList, this);
mOrderListView.setAdapter(mOrderListAdapter);
這裡可看到分為幾步:
- 聲明LayoutManager,并調用RecycleView的setLayoutManager方法進行指派
目前SDK中提供了三種LayoutManager,分别為
- LinearLayoutManager
- GridLayoutManager
- StaggeredGridLayoutManager
使用不同的LayoutManager,分别如下:
- 使用LinearLayoutManager
mLayoutManager = new LinearLayoutManager(this)
- 使用GridLayoutManager
mLayoutManager = new GridLayoutManager(this, , LinearLayoutManager.Vertical, false)
GridLayoutManager的構造有如下幾種:
/**
* Creates a vertical GridLayoutManager
*
* @param context Current context, will be used to access resources.
* @param spanCount The number of columns in the grid
*/
public GridLayoutManager(Context context, int spanCount) {
super(context);
setSpanCount(spanCount);
}
/**
* @param context Current context, will be used to access resources.
* @param spanCount The number of columns or rows in the grid
* @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link
* #VERTICAL}.
* @param reverseLayout When set to true, layouts from end to start.
*/
public GridLayoutManager(Context context, int spanCount, int orientation,
boolean reverseLayout) {
super(context, orientation, reverseLayout);
setSpanCount(spanCount);
}
在這裡,按照我們上述的聲明,其實作的效果跟LinearLayout的效果是一緻的,當SpanCount值大于1的時候,就能夠以格式的效果展現,這種切換其實還是挺簡單的,是不?
- StaggeredGridLayoutManager
StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(, StaggeredGridLayoutManager.VERTICAL);
看效果就已經能夠實作簡單的瀑布流了。
接下來還要對recycleView設定以下的方法:
-
設定hasFixedSize方法
調用此方法,可讓RecycleView保持展現的item數目,在RecycleView的實作中會有一些優化。
- 聲明Adapter,将調用RecycleView的setAdapter方法進行指派。
到這裡,除了去實作 Adapter之後,對RecycleView的初始化及使用,到此即可。
除此之外,我們還能夠調用RecycleView的addItemDecoration方法和setItemAnimator方法來自定義item的分隔線及item的動畫效果。
mOrderListView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
mOrderListView.setItemAnimator(new DefaultItemAnimator());
實作Adapter
我們實作的Adapter必須繼承于RecycleView.Adapter,如下
而需要我們去實作的方法,如下展示:
@Override
public int getItemViewType(int position) {
if (position + == getItemCount()) {
return TYPE_FOOTER;
} else {
return TYPE_ITEM;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (TYPE_ITEM == viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.order_list_item, parent, false);
return new OrderListViewHolder(view);
} else {
View view = LayoutInflater.from(mContext).inflate(R.layout.list_footer, parent, false);
return new OrderListFooterHolder(view);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof OrderListViewHolder) {
Order order = mData.get(position);
OrderListViewHolder itemHolder = (OrderListViewHolder) holder;
...
} else if (holder instanceof OrderListFooterHolder) {
OrderListFooterHolder footerHolder = (OrderListFooterHolder) holder;
...
}
}
@Override
public int getItemCount() {
return mData.size() + ;
}
static class OrderListFooterHolder extends RecyclerView.ViewHolder {
TextView itemFooter;
public OrderListFooterHolder(View itemView) {
super(itemView);
itemFooter = (TextView) itemView.findViewById(R.id.item_footer);
}
}
static class OrderListViewHolder extends RecyclerView.ViewHolder {
....
public OrderListViewHolder(View itemView) {
super(itemView);
...
}
}
在上面這個Adapter中,其實做了幾件事:
-
public int getItemViewType(int position)
根據getItemViewType傳回我們要去加載的item布局,這一個方法的實作不是必須的,在這裡隻是因為需要去加載兩個布局,是以就定義了兩個ITEM_TYPE,如果就一個布局,這方法可以不實作。
-
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
如果有不同的viewType,我們則必須根據不同的viewType來從不同的item布局中,利用LayoutInflater來加載,并建立對應的ViewHolder,是以在這裡,我們需要實作onCreateViewHolder方法,其會傳回一個RecyclerView.ViewHolder對象。
- static class OrderListFooterHolder extends RecyclerView.ViewHolder
-
static class OrderListViewHolder extends RecyclerView.ViewHolder
既然上一步傳回了一個RecyclerView.ViewHolder對象,對應的,我們就要實作自己的ViewHolder,來存儲對應的元件了,如上面的OrderListFootHolder和OrderListViewHolder。
-
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position)
有了ViewHolder之後,接下來就是要将ViewHolder和資料給綁定到一起來,則需要去調用OnBindViewHolder方法了,其參數一個為對應的ViewHolder,一個為對應的位置,通過此位置,去資料清單中擷取對應的資料。
-
public int getItemCount()
最後,我們還要實作getItemCount方法,告知RecycleView,此Adapter到底要處理多少個對象。
至此,對RecycleView的基本使用就可是這樣了。