RecycleView 是2014年Google IO 引入的新的控件,它是以 v7 support libraries的形式存在的,可以用在之前的Android系统版本。它的引入主要是用于增强ListView的功能。与其它的View不一样的地方是RecyclerView不负责子view的展现和布局工作,它关注的是子view的回收与复用。而子view的布局、装饰、动画都交给了其内部类来负责。
ViewHolder :用来放置每个item所包含子view的容器。在Adapter中负责创建和填充ViewHolder Adapter :用于绑定数据和ViewHolder LayoutManager :布局管理器,负责子View的位置安排 ItemDecoration :用来装饰子view ItemAnimator :用于添加子View,增加删除的动画
RecycleView的简单使用 下面就由简单到复杂一步一步介绍它的使用。
1.在项目中引入recycleview的依赖关系。
compile 'com.android.support:recyclerview-v7:23 .4 .0 '
如果大家不是很清楚recycleview的版本号的话,可以使用project structrue -> dependencies 输入recycleview,这时候会自动帮你查找对应的版本。
Adapter 负责生成出绑定数据后的ViewHolder,它继承自RecyclerView.Adapter,一般而言它有一个构造方法用于用于传入两个参数,一个是上下文内容,一个是数据列表,还可以有另外一个参数用于传入布局id。public class MyRecycleViewAdapter extends RecyclerView .Adapter<MyRecycleViewAdapter .ViewHolder> { private Context mContext; private ArrayList <String > mList; MyRecycleViewAdapter (Context context, List <String > list) { mContext = context; mList = (ArrayList <String >) list; } }
由于它继承自RecyclerView.Adapter所以必须覆写: onCreateViewHolder onBindViewHolder getItemCount@Override public ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) { LayoutInflater mInflater = LayoutInflater.from(parent.getContext()); View itemView = mInflater.inflate(R.layout.recycleview_item, parent, false ); return new ViewHolder (itemView); } @Override public void onBindViewHolder (ViewHolder holder, int position) { String content = mList.get(position); holder.mContentView.setText(content); } @Override public int getItemCount () { return mList.size(); }
onCreateViewHolder 负责使用item layout 初始化出一个ItemView,再将ItemView传入ViewHoder,在ViewHolder中创建出构成ItemView的每个子View然后作为参数传递给onBindViewHolder,onBindViewHolder有两个参数,一个是onCreateViewHolder创建的ViewHolder,另一个是数据对应的位置,可以通过第二个参数重数据源中取出数据,然后和ViewHoder中的控件绑定。
下面是ViewHolder的实现:
public class ViewHolder extends RecyclerView .ViewHolder { public TextView mContentView; public ViewHolder (View itemView) { super (itemView); mContentView = (TextView ) itemView.findViewById(R .id.listview_item); } }
最后初始化整个RecycleView:
public class MainActivity extends AppCompatActivity { private RecyclerView mRecycleView = null; @Override protected void onCreate(Bundle savedInstanceState ) { super.onCreate(savedInstanceState ) ; setContentView(R.layout .activity_main ) ; mRecycleView = (RecyclerView) findViewById(R.id .recycle_view ) ; mRecycleView.setLayoutManager(new GridLayoutManager(this ,2) ); List<String> stringlist = new ArrayList<>() ; for (int i =0 ;i<100 ;i++) { stringlist.add("Item " + i); } mRecycleView.setAdapter(new MyRecycleViewAdapter(this ,stringlist ) ); mRecycleView.setItemAnimator(new DefaultItemAnimator() ); } }
RecycleView组成 RecyclerView.LayoutManager RecyclerView.ItemDecoration RecyclerView.ItemAnimator ItemAnimator 用于在往RecycleView中添加删除或者移动Item的时候添加动画。默认情况下使用的是DefaultItemAnimator,在实际项目的时候会需要实现这个部分,如果大家有这种需求可以参考:https://github.com/wasabeef/recyclerview-animators
多类型Item布局 在RecyclerView.Adopter中要实现多类型Item布局需要覆写如下方法:
public int getItemViewType (int position)
并按照如下方法重新修改Adapter:
public class MyRecycleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private Context mContext; private ArrayList<String> mList; private enum ITEM_TYPE { TYPE_ONE, TYPE_TWO }; @Override public int getItemViewType(int position ) { return (position % 2 == 0 ) ? ITEM_TYPE .TYPE_ONE . ordinal() :ITEM_TYPE .TYPE_TWO . ordinal() ; } MyRecycleViewAdapter(Context context , List<String> list ) { mContext = context; mList = (ArrayList<String>) list ; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent , int viewType ) { LayoutInflater mInflater = LayoutInflater . from(parent.getContext() ); View itemView = null; if (viewType == ITEM_TYPE .TYPE_ONE . ordinal() ) { itemView = mInflater.inflate(R . layout.recycleview_item, parent, false ); return new ViewHolder(itemView ) ; }else { itemView = mInflater.inflate(R . layout.recycleview_two, parent, false ); return new ViewHolderTwo(itemView ) ; } } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder , int position ) { String content = mList.get(position); if (holder instanceof MyRecycleViewAdapter.ViewHolder) { ((ViewHolder) holder).mContentView.setText(content ) ; }else if (holder instanceof MyRecycleViewAdapter.ViewHolderTwo) { ((ViewHolderTwo) holder).mImageView.setImageResource(R.mipmap .ic_launcher ) ; ((ViewHolderTwo) holder).mContentView.setText(content ) ; } } @Override public int getItemCount() { return mList.size() ; } public class ViewHolder extends RecyclerView.ViewHolder { public TextView mContentView; public ViewHolder(View itemView ) { super(itemView); mContentView = (TextView) itemView.findViewById(R.id .listview_item ) ; } } public class ViewHolderTwo extends RecyclerView.ViewHolder { public TextView mContentView; private ImageView mImageView; public ViewHolderTwo(View itemView ) { super(itemView); mImageView = (ImageView) itemView.findViewById(R.id .imageicon ) ; mContentView = (TextView) itemView.findViewById(R.id .itemtext ) ; } } }
添加ItemDecoration 首先创建一个新的类继承自RecyclerView.ItemDecoration。https://gist.github.com/alexfu/0f464fc3742f134ccd1e/
class ItemDecortion extends RecyclerView.ItemDecoration { private static final int [] ATTRS = new int [] { android.R . attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public ItemDecortion(Context context , int orientation ) { final TypedArray a = context.obtainStyledAttributes(ATTRS) ; mDivider = a.getDrawable(0) ; a.recycle() ; setOrientation(orientation ) ; } public void setOrientation(int orientation ) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation" ) ; } mOrientation = orientation; } @Override public void onDrawOver(Canvas c , RecyclerView parent , RecyclerView.State state ) { if (mOrientation == VERTICAL_LIST) { drawVertical(c , parent ) ; } else { drawHorizontal(c , parent ) ; } } public void drawVertical(Canvas c , RecyclerView parent ) { final int left = parent.getPaddingLeft() ; final int right = parent.getWidth() - parent.getPaddingRight() ; final int childCount = parent.getChildCount() ; for (int i = 0 ; i < childCount; i++) { final View child = parent.getChildAt(i ) ; final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams() ; final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight() ; mDivider.setBounds(left , top , right , bottom ) ; mDivider.draw(c); } } public void drawHorizontal(Canvas c , RecyclerView parent ) { final int top = parent.getPaddingTop() ; final int bottom = parent.getHeight() - parent.getPaddingBottom() ; final int childCount = parent.getChildCount() ; for (int i = 0 ; i < childCount; i++) { final View child = parent.getChildAt(i ) ; final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams() ; final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight() ; mDivider.setBounds(left , top , right , bottom ) ; mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect , View view , RecyclerView parent , RecyclerView.State state ) { if (mOrientation == VERTICAL_LIST) { outRect.set(0 , 0 , 0 , mDivider.getIntrinsicHeight() ); } else { outRect.set(0 , 0 , mDivider.getIntrinsicWidth() , 0 ); } } }
然后在设置adapter之前,使用addItemDecoration()方法添加分割线.
mRecycleView.addItemDecoration(new ItemDecortion(this ,ItemDecortion.VERTICAL_LIST) ); mRecycleView.setAdapter(new MyRecycleViewAdapter(this ,stringlist ) );
添加点击事件: ListView 和RecycleView最大的不同就是没有OnItemClickListener来识别item的点击,我们必须自己通过扩展RecyclerView.OnItemTouchListener类来实现这个功能。
private interface onClickListener { public void onClick (View view, int position) ; public void onLongClick (View view,int position) ; }
public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener { private GestureDetector gestureDetector; private MainActivity . onClickListener clickListener; public RecyclerTouchListener(Context context , final RecyclerView recyclerView , final MainActivity.onClickListener clickListener ) { this.clickListener = clickListener; gestureDetector = new GestureDetector(context , new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapUp(MotionEvent e ) { return true ; } public void onLongPress(MotionEvent e ) { View child = recyclerView.findChildViewUnder(e .getX () , e.getY() ); if (child != null && clickListener != null) { clickListener.onLongClick(child , recyclerView .getChildPosition (child ) ); } } }); } public boolean onInterceptTouchEvent(RecyclerView rv , MotionEvent e ) { View child = rv.findChildViewUnder(e .getX () , e.getY() ); if (child != null && clickListener != null && gestureDetector.onTouchEvent(e ) ) { clickListener.onClick(child , rv .getChildPosition (child ) ); } return false ; } public void onTouchEvent(RecyclerView rv , MotionEvent e ) { } public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept ) { } }
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext () , recyclerView, new ClickListener() { public void onClick(View view , int position ) { Movie movie = movieList.get(position); Toast . makeText(getApplicationContext () , movie.getTitle() + " is selected!" , Toast.LENGTH_SHORT).show() ; } public void onLongClick(View view , int position ) { } }));
增删改Item项 在ListView中每当Adapter数据项改变的时候一般执行notifyDataSetChanged()来通知数据集的改变,但是RecyclerView.Adapter 提供了 notifyItemInserted(), notifyItemChanged() 和 notifyItemRemoved()三个方法来通知数据集的修改。