Android(安卓)RecyclerView
RecyclerView作为升级版的ListView和GridView,更加的先进和灵活。接下来就介绍下RecyclerView的用法。
首先,在gradle脚本中添加,
compile 'com.android.support:recyclerview-v7:23.0.1'
在布局中引用
<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=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="wrap_content" android:layout_height="wrap_content" /></RelativeLayout>
RecyclerView是没有divider属性的。
Adapter的编写,这里的Adapter应该继承public static abstract class Adapter {},可以看到,这里内部就有一个ViewHolder,我们只需要实现自己的ViewHolder就好,我们必须要实现Adapter的3个方法:
- onCreateViewHolder 创建holder
- onBindViewHolder 绑定holder
getItemCount 得到view的数目
最终的代码我会在后面给出。设置分割线
recyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this, DividerItemDecoration.VERTICAL_LIST));
我们通过addItemDecoration来添加分割线,DividerItemDecoration这个类就是实现分割线的。
这个类我是抄网上的。。。
package gl.com.as;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;/** * Created by mac on 15-10-9. */public class DividerItemDecoration 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 DividerItemDecoration(Context context,int orienttation){ final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orienttation); } public void setOrientation(int orientation){ if (orientation!=HORIZONTAL_LIST && orientation!=VERTICAL_LIST){ throw new IllegalArgumentException("invalid orientation"); } mOrientation=orientation; } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mOrientation==VERTICAL_LIST){ drawVertival(c,parent); }else{ drawHorizontal(c,parent); } } /** * draw vertival line * @param c * @param parent */ public void drawVertival(Canvas c,RecyclerView parent){ final int left = parent.getPaddingLeft(); final int right = 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,bottom,right); mDivider.draw(c); } } /** * draw horizaontal line * @param c * @param parent */ 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.getIntrinsicWidth(); mDivider.setBounds(left,top,right,bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { if (mOrientation==VERTICAL_LIST){ outRect.set(0,0,0,mDivider.getIntrinsicHeight()); }else{ outRect.set(0,0,mDivider.getIntrinsicWidth(),0); } }}
上面的类就实现了横 竖2中分割线,想实现其他样式的参考张鸿洋,
LayoutManager
这里有3种:
1.LinearLayoutManager(..) listview风格
2.GridLayoutManager(..) GridView
3.StaggeredGridLayoutManager(..) 同样可以实现gridview,还可以实现瀑布流,只要设置好高度就行。添加增加删除动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
这是系统默认的动画,我们当然也可以定制自己的动画啦。具体实现参考DefaultItemAnimator类的实现,不过github上 有很多牛人已经做了很多了。小伙伴们可以去github上找找。Github上的动画
- 监听器的实现
RecyclerView没有提供设置监听器的方法 ,不过没关系。我们可以实现自己的回调接口
public interface OnItemClickListener { void onClick(int pos); void onLongClick(int pos); } private OnItemClickListener listener; public void setOnclickListener(OnItemClickListener listener){ this.listener=listener; } //然后在onBindViewHolder中添加 if (listener!=null){ holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos=holder.getLayoutPosition(); listener.onClick(pos); } }); holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { int pos = holder.getLayoutPosition(); listener.onLongClick(pos); return false; } }); }
接下来,在Activity中
mAdapter.setOnclickListener(new RecyclerViewAdapter.OnItemClickListener() { @Override public void onClick(int pos) { Toast.makeText(MainActivity.this,pos+"click",Toast.LENGTH_SHORT).show(); } @Override public void onLongClick(int pos) { Toast.makeText(MainActivity.this,pos+"long click",Toast.LENGTH_SHORT).show(); } });
- 多布局的实现
重写getItemViewType(int pos)方法 ,onCreateViewHolder(ViewGroup parent, int viewType),第二个参数就position对应的type了,我们只需要根据viewType返回不同的viewholder即可。
下面是Adapter的完整代码
package gl.com.as;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * Created by mac on 15-10-9. */public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{ private Context context; private List<String> mDatas; private List<Integer> mHeight; public RecyclerViewAdapter(Context context,List<String> mDatas){ this.context=context; this.mDatas=mDatas; mHeight = new ArrayList<Integer>(); for (int i =0;i<mDatas.size();i++){ mHeight.add((int) (100+Math.random()*300)); } } public interface OnItemClickListener { void onClick(int pos); void onLongClick(int pos); } private OnItemClickListener listener; @Override public int getItemViewType(int position) { if (position%2==0){ return 0; }else{ return 1; } } public void setOnclickListener(OnItemClickListener listener){ this.listener=listener; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ViewHolder holder=null; Log.e("tag","this is on onCreateViewHolder"+viewType); switch (viewType){ case 0: holder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.rccyclerview_item,parent,false)); break; default: holder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.rccyclerview_item2,parent,false)); break; } return holder; } @Override public void onBindViewHolder(final ViewHolder holder, int position) { ViewGroup.LayoutParams lp = holder.textView.getLayoutParams(); lp.height=mHeight.get(position); holder.textView.setLayoutParams(lp); holder.textView.setText(mDatas.get(position)); if (listener!=null){ holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos=holder.getLayoutPosition(); listener.onClick(pos); } }); holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { int pos = holder.getLayoutPosition(); listener.onLongClick(pos); return false; } }); } } @Override public int getItemCount() { return mDatas.size(); } public void addData(int position){ mDatas.add(position,"Insert One"); notifyItemInserted(position); } public void removeData(int position){ mDatas.remove(position); notifyItemRemoved(position); } class ViewHolder extends RecyclerView.ViewHolder { private TextView textView; public ViewHolder(View itemView) { super(itemView); textView= (TextView) itemView.findViewById(R.id.id_text); } }}
上图:
- 下拉刷新和上拉加载更多
利用SwipeRefreshLayout,因为SwipeRefreshLayout没有上拉加载更多,所以我这里给出大概思路。
<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=".MainActivity"> <android.support.v4.widget.SwipeRefreshLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/image" > <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:divider="#dddd0000" android:dividerHeight="10dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </android.support.v4.widget.SwipeRefreshLayout> <ImageView android:id="@+id/image" android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_launcher" android:visibility="gone" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" /></RelativeLayout>
其实这里用FrameLayout更好一点,我这里为了省事。下拉刷新实现SwipeRefreshLayout.OnRefreshListener接口就好。上拉刷新的话
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int lastVisiableItem = ((LinearLayoutManager)manager) .findLastVisibleItemPosition(); if (lastVisiableItem+1==mDatas.size()){ image.setVisibility(View.VISIBLE); //do something } } });
这里是LinearLayoutManager,其他2个的话做相应的逻辑处理。关于SwipeRefreshLayout封装上拉加载更多,网上很多人写了。百度。。。
- 头部尾部问题
关于Recycler添加头部尾部问题是在蛋疼。不过好在有ListView,我们可以参考ListView的实现方法来实现。
以下为ListView的部分源码,以添加headview为例:
private ArrayList<FixedViewInfo> mHeaderViewInfos = Lists.newArrayList(); private ArrayList<FixedViewInfo> mFooterViewInfos = Lists.newArrayList();
public void addHeaderView(View v, Object data, boolean isSelectable) { final FixedViewInfo info = new FixedViewInfo(); info.view = v; info.data = data; info.isSelectable = isSelectable; mHeaderViewInfos.add(info); mAreAllItemsSelectable &= isSelectable; // Wrap the adapter if it wasn't already wrapped. if (mAdapter != null) { if (!(mAdapter instanceof HeaderViewListAdapter)) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter); } // In the case of re-adding a header view, or adding one later on, // we need to notify the observer. if (mDataSetObserver != null) { mDataSetObserver.onChanged(); } } }
关键就在于HeaderViewListAdapter。根据HeaderViewListAdapter的代码依葫芦画瓢就行了。小弟在这里就不献丑了。给出参考资料,去看这位大神的代码吧。添加头部尾部
好累,到这里就完了。
参考资料:添加头尾
参考资料:张鸿洋
更多相关文章
- Android代码中添加打印信息
- 安卓 Android之开发简单小应用(二)
- android mtk6592 添加led三色灯,红色蓝色绿色
- android Activity关闭动画 附左右动画anim
- Android布局管理器-使用TableLayout表格布局管理器实现简单的用
- Fragment的使用
- AndroidStudio常见问题
- flutter的AndroidX版本适配
- 十四、ContentProvider往通讯录添加联系人和获取联系人