標籤(空格分隔): 安卓UIjava
RecyclerView相對於ListView而言提供設置整個數據的展現佈局,對應方法源碼:android
/** * Set the {@link LayoutManager} that this RecyclerView will use. * * <p>In contrast to other adapter-backed views such as {@link android.widget.ListView} * or {@link android.widget.GridView}, RecyclerView allows client code to provide custom * layout arrangements for child views. These arrangements are controlled by the * {@link LayoutManager}. A LayoutManager must be provided for RecyclerView to function.</p> * * <p>Several default strategies are provided for common uses such as lists and grids.</p> * * @param layout LayoutManager to use */
public void setLayoutManager(LayoutManager layout) {
......
}
複製代碼
目前實現RecyclerView.LayoutManager的LayoutManager有: LinerLayoutManager:內部元素以垂直或者水平列表方式展現Item; GridLayoutManager:以網格方式展現Item; StaggeredGridLayoutManager:以瀑布流方式展現Item; 所以能夠看到RecyclerView比ListView固定的垂直佈局要靈活的多;設計模式
RecyclerView支持對於Item的特殊設定,好比支持item添加和移除的動畫、好比支持設置item之間間隔樣式;app
/** * Sets the {@link ItemAnimator} that will handle animations involving changes * to the items in this RecyclerView. By default, RecyclerView instantiates and * uses an instance of {@link DefaultItemAnimator}. Whether item animations are * enabled for the RecyclerView depends on the ItemAnimator and whether * the LayoutManager {@link LayoutManager#supportsPredictiveItemAnimations() * supports item animations}. * * @param animator The ItemAnimator being set. If null, no animations will occur * when changes occur to the items in this RecyclerView. */
public void setItemAnimator(ItemAnimator animator) {
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
mItemAnimator.setListener(null);
}
mItemAnimator = animator;
if (mItemAnimator != null) {
mItemAnimator.setListener(mItemAnimatorListener);
}
}
/** * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can * affect both measurement and drawing of individual item views. * * <p>Item decorations are ordered. Decorations placed earlier in the list will * be run/queried/drawn first for their effects on item views. Padding added to views * will be nested; a padding added by an earlier decoration will mean further * item decorations in the list will be asked to draw/pad within the previous decoration's * given area.</p> * * @param decor Decoration to add * @param index Position in the decoration chain to insert this decoration at. If this value * is negative the decoration will be added at the end. */
public void addItemDecoration(ItemDecoration decor, int index) {
if (mLayout != null) {
mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll or"
+ " layout");
}
if (mItemDecorations.isEmpty()) {
setWillNotDraw(false);
}
if (index < 0) {
mItemDecorations.add(decor);
} else {
mItemDecorations.add(index, decor);
}
markItemDecorInsetsDirty();
requestLayout();
}
複製代碼
RecyclerView自己就是用來展現集合數據源的View,適配器本質是一個支持範型的設計模式,即實現將不一樣的數據和展現(邏輯)作適配,所以適配器的關鍵在於提供一些方法來綁定數據和展現的特殊關係;每個具體的使用者都必須本身重寫這些方法,來表達如何匹配; RecyclerView.Adapter這個抽象類定義以下:less
/** * Base class for an Adapter * * <p>Adapters provide a binding from an app-specific data set to views that are displayed * within a {@link RecyclerView}.</p> * * @param <VH> A class that extends ViewHolder that will be used by the adapter. */
public abstract static class Adapter<VH extends ViewHolder> {
......
}
複製代碼
在RecyclerView.Adapter會須要用到RecyclerView.ViewHolder,ViewHolder有什麼做用?參考Google官方說明:ide
/** * A ViewHolder describes an item view and metadata about its place within the RecyclerView. * * <p>{@link Adapter} implementations should subclass ViewHolder and add fields for caching * potentially expensive {@link View#findViewById(int)} results.</p> * * <p>While {@link LayoutParams} belong to the {@link LayoutManager}, * {@link ViewHolder ViewHolders} belong to the adapter. Adapters should feel free to use * their own custom ViewHolder implementations to store data that makes binding view contents * easier. Implementations should assume that individual item views will hold strong references * to <code>ViewHolder</code> objects and that <code>RecyclerView</code> instances may hold * strong references to extra off-screen item views for caching purposes</p> */
public abstract static class ViewHolder {
......
}
複製代碼
ViewHolder實際上就是提供將每一個Item的View和數據源Data關聯起來的橋樑,ViewHolder內部會定義Item View的子元素,後續再根據Adapter提供的方法,將數據源的數據關聯到ViewHolder的View子元素 以下使用:佈局
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView show_tv;
public MyViewHolder(View itemView) {
super(itemView);
show_tv = (TextView) itemView.findViewById(R.id.item_show_tv);
}
}
複製代碼
Adapater提供了兩個方法,一個用來表示每一個Item對應的View展現,一個用來表示每一個Item如何展現數據源的數據:動畫
先參考官方定義: /**ui
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 每一個Item展現的view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item_view, parent, false);
// 持有展現View的viewholder,viewholder後續會和數據源對應
MyViewHolder viewHolder = new MyViewHolder(v);
return viewHolder;
}
複製代碼
onCreateViewHolder方法須要定義每一個Item對應展現的View,同時將View映射到ViewHolder對象this
先參考官方定義:
/** * Called by RecyclerView to display the data at the specified position. This method should * update the contents of the {@link ViewHolder#itemView} to reflect the item at the given * position. * Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method * again if the position of the item changes in the data set unless the item itself is * invalidated or the new position cannot be determined. For this reason, you should only * use the <code>position</code> parameter while acquiring the related data item inside * this method and should not keep a copy of it. If you need the position of an item later * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will * have the updated adapter position. * Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can * handle efficient partial bind. */
public abstract void onBindViewHolder(VH holder, int position);
複製代碼
官方文檔已經作了說明,onBindViewHolder提供了將對應某個位置的數據源更新到對應到對應的ViewHolder,進而更新到對應的Item View; 具體使用參考:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// 將數據綁定到對應位置的ViewHolder
holder.show_tv.setText(mData.get(position));
}
複製代碼
顯而易見,onBindViewHolder方法就是將數據源數據綁定更新到ViewHolder,進而將數據映射到每一個Item View; onBindViewHolder方法須要解決兩個關鍵問題:一、當數據源更新的時候,每一個元素都會再調用這個方法更新樣式嗎?二、當數據源不變,只須要更新某個Item UI展現,如何操做? 具體的操做能夠參考onBindViewHolder的源碼實現,即參考方法bindViewHolder、tryBindViewHolderByDeadline的具體實現來解答此問題; 除了以上方法,在具體實現過程當中須要設置Adapter的數據源和重寫getItemCount方法,來實現Adapter更新數據; RecyclerView的item不像ListView那樣提供點擊監聽,咱們須要自定義Item的監聽時間;Item本質是一個View,能夠自定義實現各類各樣的監聽事件,好比單擊、長按、手勢划動等等; 另外上面提供的重寫方法是最基本的,針對不一樣使用場景,各位作不一樣的定製化;
ItemTouchHelper是一個處理RecyclerView的滑動刪除和拖拽的輔助類,RecyclerView 的item拖拽移動和滑動刪除就靠它來實現;官方文檔介紹以下:
/** * This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView. * It works with a RecyclerView and a Callback class, which configures what type of interactions * are enabled and also receives events when user performs these actions. * Depending on which functionality you support, you should override * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)} and / or * {@link Callback#onSwiped(ViewHolder, int)}. * This class is designed to work with any LayoutManager but for certain situations, it can be * optimized for your custom LayoutManager by extending methods in the * {@link ItemTouchHelper.Callback} class or implementing {@link ItemTouchHelper.ViewDropHandler} * interface in your LayoutManager. * By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. You can * customize these behaviors by overriding {@link Callback#onChildDraw(Canvas, RecyclerView, * ViewHolder, float, float, int, boolean)} * or {@link Callback#onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, * boolean)}. * Most of the time you only need to override <code>onChildDraw</code>. */
public class ItemTouchHelper extends RecyclerView.ItemDecoration implements RecyclerView.OnChildAttachStateChangeListener {
......
}
複製代碼
itemTouchHelper須要與recyclerView綁定纔有效果,參考方法attachToRecyclerView:
/** * Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already * attached to a RecyclerView, it will first detach from the previous one. You can call this * method with {@code null} to detach it from the current RecyclerView. * @param recyclerView The RecyclerView instance to which you want to add this helper or {@code null} if you want to remove ItemTouchHelper from the current RecyclerView. */
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
......
}
複製代碼
根據ItemTouchHelper.Callback能夠實現對Item的添加、刪除的處理;
addOnScrollListener用來監聽Scroll滑動,根據對應的LayoutManager能夠實現滑動時候UI的各類展現效果;