編輯:關於Android編程
今年Google I/0大會,Google開放了兩個全新的視圖:RecyclerView和CardView。這篇文章會提供關於RecylerView的簡介。
RecylerView作為support-library發布出來,這對開發者來說絕對是個好消息。因為可以在更低的Android版本上使用這個新視圖。下面我們看如何獲取RecylerView。首先打開Android SDK Manager,然後更新Extras->Android Support Library即可。
然後在本地../sdk/extras/android/support/v7中找到recyclerview。我已經將下載好的Recyclerview整理成一個Eclipse可編譯的Library工程上傳到Github,有需求的同學請戳鏈接。
示例程序
我將通過RecylerView制作一個橫向滑動的“ListView”,下面是示例程序的截圖。並在ActionBar上設置數據的添加/刪除操作。請同學們注意,RecyclerView的接口Google可能會繼續優化和修改,所以最終的版本可能和我提供的程序有出入。Demo程序Github鏈接。
為什麼要使用RecyclerView?
Google在是這樣描述RecyclerView的:
"A flexible view for providing a limited window into a large data set."
所以RecyclerView適用於無法在一個屏幕范圍內展現格式一樣的數據時,需要用多行或多列來展示。例如展示聯系人,圖片,視頻等。用戶需要滑動屏幕來查看數據,這時RecyclerView的特性就有用武之地了。比如,當用戶滑動使當前一個可視的Item滑出屏幕,這個Item的視圖將會被回收並在一個新Item進入可視范圍後重新被使用。
如下圖所示,用戶滑動向上滑動左邊的RecyclerView,No.0和No.1就會滑出屏幕可視范圍,這時右圖的No.0和No.1的視圖將會被RecyclerView放入一個可重復利用的緩存中以備再次使用。
可回收利用View是個很實用的功能,它不僅可以減少CPU不斷inflate View的開銷,而且可以節省緩存View的內存開銷。
這時,你可能會問:這不是一個新功能啊!是的,我們已經在使用ListView的時候使用了這個機制,但是當使用ListView時,顯示,回收等功能是緊密耦合在一起的,Google現在發布RecyclerView,使方法更靈活,開發者也能自定義各種各樣的顯示效果。
RecyclerView不再負責顯示工作
和ListView不一樣的是,RecyclerView不再負責Item的擺放等顯示方面的功能。所有和布局、繪制等方面的工作Google都其拆分成不同的類進行管理。所以開發者可以自定義各種各樣滿足定制需求的的功能類。
下面是一些和RecyclerView相關的非常重要的類列表。
ViewHolder
關於ViewHolder,Google早就推薦開發者使用,但也只是建議。但是現在,RecyclerView.Adapter最終要求開發者必須使用ViewHolder。如果你還對ViewHolder不了解,請閱讀Android training session。
Demo通過繼承RecyclerView.ViewHolder來實現自定義:
public class MyViewHolder extends ViewHolder implements OnClickListener,OnLongClickListener{ public ImageView iv; public TextView tv; private MyItemClickListener mListener; private MyItemLongClickListener mLongClickListener; public MyViewHolder(View rootView,MyItemClickListener listener,MyItemLongClickListener longClickListener) { super(rootView); iv = (ImageView)rootView.findViewById(R.id.item_iv); tv = (TextView)rootView.findViewById(R.id.item_tv); this.mListener = listener; this.mLongClickListener = longClickListener; rootView.setOnClickListener(this); rootView.setOnLongClickListener(this); } /** * 點擊監聽 */ @Override public void onClick(View v) { if(mListener != null){ mListener.onItemClick(v,getPosition()); } } /** * 長按監聽 */ @Override public boolean onLongClick(View arg0) { if(mLongClickListener != null){ mLongClickListener.onItemLongClick(arg0, getPosition()); } return true; } }
RecyclerView.Adapter
Adapter負責扮演兩個角色:不僅為底部數據提供支持而且還負責為數據創建合適的視圖。Adapter適用在Android很多控件,例如ListView、AutoCompleteTextView等。
繼承RecyclerView.Adapter需要實現以下三個方法:
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) public void onBindViewHolder(ViewHolder holder,int position) public int getItemCount() Demo中的Adapter: [java] view plain copy public class MyAdapter extends Adapter<MyViewHolder> { private List<MyItemBean> mData; private MyItemClickListener mItemClickListener; private MyItemLongClickListener mItemLongClickListener; public MyAdapter(List<MyItemBean> data){ this.mData = data; } @Override public int getItemCount() { return mData.size(); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { MyItemBean bean = mData.get(position); holder.tv.setText(bean.tv); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent,false); MyViewHolder vh = new MyViewHolder(itemView,mItemClickListener,mItemLongClickListener); return vh; } }
onCreateViewHolder中負責為Item創建視圖,onBindViewHolder負責將數據綁定到Item的視圖上。
RecyclerView.LayoutManager
LayoutManager是RecyclerView中最有意思的類。該類負責將每個Item視圖在RecylerView中的布局。目前Google提供了LayoutManager的一個子類:LinearLayoutManager。LinearLayoutManager提供了橫向和豎向兩種布局,Demo就是使用LinearLayoutManger的橫向布局實現的。
如果要自定義LayoutManager,需要實現一個abstract方法
public LayoutParams generateDefaultLayoutParams()
Demo中為RecylerView添加LinearLayoutManager的片段:
MyLayoutManager manager = new MyLayoutManager(this);
manager.setOrientation(LinearLayout.HORIZONTAL);//默認是LinearLayout.VERTICAL
mRecyclerView.setLayoutManager(manager);
LinearLayoutManager提供了如下幾個方法來幫助開發者獲取屏幕上的頂部item和底部item:
findFirstVisibleItemPosition()
findFirstCompletelyVisibleItemPosition()
findLastVisibleItemPosition()
findLastCompletelyVisibleItemPosition()
RecyclerView.ItemDecoration
通過ItemDecoration可以使各個Item在視覺上相互分開,其實和ListView的Divider很像。ItemDecoration並不是RecyclerView必須設置的,開發者可以不設置或者設置多個Decoration。RecyclerView會遍歷所有的ItemDecoration並調用各自的繪圖方法。
繼承ItemDecoration需要實現以下三個方法:
public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
public void getItemOffset(Rect outRect,int itemPosition,RecyclerView parent)
LayoutManager會調用getItemOffset方法來計算每個Item的Decoration合適的尺寸。
Demo中自定義了一個ItemDecoration來實現ListView的Divider效果:
public class MyDecoration extends ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; private Drawable mDivider; public MyDecoration(Context ctx){ final TypedArray a = ctx.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); } @Override public void onDraw(Canvas c, RecyclerView parent, State state) { int top = parent.getPaddingTop(); int bottom = parent.getHeight() - parent.getPaddingBottom(); int childCount = parent.getChildCount(); for(int i=0;i < childCount;i++){ View child = parent.getChildAt(i); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)child.getLayoutParams(); int left = child.getRight() + layoutParams.rightMargin; int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } }
RecyclerView.ItemAnimatior
當Item有以下三種操作時ItemAnimatior會為RecyclerView提供動畫效果:
刪除某一個Item
添加一個新的Item
移動某個Item
Google提供了一個名為DefaultItemAnimator的默認ItemAnimator供開發者使用。如果開發者不為RecyclerView設置ItemAnimator,RecyclerView也會使用默認的DefaultItemAnimator。
顯然,為了讓動畫效果起效,開發者必須通知Adapter數據有改變。之前我們使用Adapter時會調用notifyDataSetChanged()來通知Adapter數據改變並更新視圖,現在RecyclerView,Adapter提供了許多notifyXyz()方法,例如Demo中使用了以下兩個方法:
public final void notifyItemInserted(int position)
public final void notifyItemRemoved(int position)
使用RecyclerView
首先,我們先看如何在xml中使用RecyclerView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.xmy.recylerviewdemo.MainActivity" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </RelativeLayout>
然後需要開發者在代碼中實現RecyclerView的組裝,大體可概括為以下步驟:
實例化RecyclerView
為RecyclerView設置LayoutManager
為RecyclerView設置Adapater
如果有需求,可以設置一個或多個ItemDecorations,當然,也可以不設置
如果有需求,可以設置ItemAnimator
Android Window、PhoneWindow、Activity學習心得第二彈Window 分析這裡先給出部分源碼 目錄(Android 4.4/framework
Android的ListView是應用最廣的一個組件,功能強大,擴展性靈活(不局限於ListView本身一個類),前面的文章有介紹分組,拖拽,3D立體,游標,圓角,而今天
這個世界就是這麼奇妙,明明手機賣的非常好,還要做手機助手,當然了我只當是給客戶的福利。VIVO除了vivo手機助手,小米也有小米手機助手。那麼小米手機助手可
本文與《利用adt-bundle輕松搭建Android開發環境與Hello world(Windows) 》是姊妹篇,只是這次操作換成了Linux 。拿Ubuntu做例子