RecyclerView详解– –使用篇
概述
RecyclerView可以完全代替ListView、GridView,整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现很多让人惊艳的效果,而且实现效果也是非常的简单。
注:本例子中不仅实现了上拉刷新还实现了下拉加载,下拉加载使用的是v4包中的SwipeRefreshLayout
首先我们需要添加需要的依赖:
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
接下来就是准备工作了
item布局:item_all_cardview.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="140dp"
android:layout_marginBottom="3dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="3dp"
android:orientation="vertical"
app:cardCornerRadius="5dp"
app:elevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/all_recy_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:text="TITLE"
android:textColor="#4152B6"
android:textSize="17sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/all_recy_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10sp"
android:src="@mipmap/ic_cloud_white_24dp"
android:layout_marginTop="4dp"/>
</LinearLayout>
<TextView
android:id="@+id/all_recy_context"
android:layout_width="match_parent"
android:layout_height="70sp"
android:layout_marginLeft="12dp"
android:layout_marginTop="5dp"
android:text="体验清爽的Material Design风格的app!"
android:textSize="15sp"
android:lines="3"
android:ellipsize="end"
android:textStyle="normal" />
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="3dp"
android:background="@drawable/line" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:orientation="horizontal">
<TextView
android:id="@+id/all_recy_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:text="分组"
android:textColor="#FE6398"
android:textSize="14sp" />
<TextView
android:id="@+id/all_recy_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="2016/05/28 23:50:20"
android:textColor="#FE6398"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
Activity布局:content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/base_swipe_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_gravity="bottom|end"
android:layout_marginBottom="12dp"
android:layout_marginEnd="12dp"
android:layout_marginLeft="@dimen/fab_margin"
android:layout_marginRight="@dimen/fab_margin"
android:clickable="true"
android:focusable="true"
android:src="@mipmap/ic_add_white_48dp"
/>
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
布局的工作已经完成,如果大家想实现点击item显示出波纹状态可以在drawable中添加样式文件
recycler_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#cfd8dc"></solid>
</shape>
</item>
</selector>
准备工作做完之后就是代码部分了,首先咱们先写一个实体类
AllBean.java
/**
* Created by TangRen on 2016-05-29.
*/
public class AllBean {
private String title;
private String context;
private String group;
private String date;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
接下来就是重点了,首先咱们先自定义一个ViewHolder,需继承RecyclerView.ViewHolder
并实现 View.OnClickListener, View.OnLongClickListener
接口
AllViewHolder.java
/**
* Created by TangRen on 2016-05-29.
*/
public class AllViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public TextView textView1, textView2, textView3, textView4;
public ImageView imageView;
public Context mContext;
//item的点击事件
private CustomItemClickListener mListener;
//item长按事件
private CustomItemLongClickListener mLongListener;
public AllViewHolder(Context mContext, View itemView, CustomItemClickListener mListener, CustomItemLongClickListener mLongListener) {
super(itemView);
this.mContext = mContext;
textView1 = (TextView) itemView.findViewById(R.id.all_recy_title);
textView2 = (TextView) itemView.findViewById(R.id.all_recy_context);
textView4 = (TextView) itemView.findViewById(R.id.all_recy_group);
textView3 = (TextView) itemView.findViewById(R.id.all_recy_date);
imageView = (ImageView) itemView.findViewById(R.id.all_recy_image);
this.mListener = mListener;
this.mLongListener = mLongListener;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
imageView.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showNewsDetail(getPosition());
}
});
}
private void showNewsDetail(int position) {
Toast.makeText(mContext, position + "", Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(View v) {
if (mListener != null) {
mListener.onItemClick(v, getPosition());
//波纹状态 itemView.setBackgroundResource(R.drawable.recycler_bg);
}
}
//长按事件
@Override
public boolean onLongClick(View v) {
itemView.setBackgroundResource(R.drawable.recycler_bg);
if (mLongListener != null) {
mLongListener.onItemLongClick(v, getPosition());
//波纹状态 itemView.setBackgroundResource(R.drawable.recycler_bg);
}
return true;
}
}
点击事件,长按事件咱们自己定义一个接口
点击事件CustomItemClickListener.java
/**
* Created by TangRen on 2016-05-29.
*/
public interface CustomItemClickListener {
public void onItemClick(View view, int postion);
}
长按事件CustomItemLongClickListener.java
/**
* Created by TangRen on 2016-05-29.
*/
public interface CustomItemLongClickListener {
public void onItemLongClick(View view, int postion);
}
上拉加载是咱们自己添加的所以需要让其添加在recyclerView的尾部
FootViewHolder.java
/**
* Created by TangRen on 2016-05-30.
*/
public class FootViewHolder extends RecyclerView.ViewHolder {
public FootViewHolder(View itemView) {
super(itemView);
}
}
接下来是重中之重 RecyclerView.Adapter适配器的自定义
AllRecycleAdapter.java
/**
* Created by TangRen on 2016-05-29.
*/
public class AllRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
private List<AllBean> mList = new ArrayList<AllBean>();
private LayoutInflater mInflater;
private static final int TYPE_ITEM = 0;
private static final int TYPE_FOOTER = 1;
private CustomItemClickListener mListener;
private CustomItemLongClickListener mLonglistener;
public AllRecycleAdapter(Context context, List<AllBean> list) {
mContext = context;
mList = list;
mInflater = LayoutInflater.from(mContext);
}
public List<AllBean> getList() {
return mList;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_all_cardview, parent, false);
AllViewHolder holder = new AllViewHolder(mContext, itemView, mListener, mLonglistener);
return holder;
} else if (viewType == TYPE_FOOTER) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.foot_view, parent, false);
FootViewHolder holder = new FootViewHolder(itemView);
return holder;
}
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Log.i("postion", position + "");
Log.i("getCount", getItemCount() + "");
if (position == getItemCount() - 1)
return;
AllBean allBean = mList.get(position);
if (allBean == null)
return;
AllViewHolder mHolder = (AllViewHolder) holder;
binData(allBean, mHolder.textView1, mHolder.textView2, mHolder.textView3, mHolder.textView4, mHolder.imageView);
}
@Override
public int getItemCount() {
return mList.size() == 0 ? 0 : mList.size() + 1;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
if (position + 1 == getItemCount()) {
return TYPE_FOOTER;
}
return TYPE_ITEM;
}
private void binData(AllBean allBean, TextView textView1, TextView textView2, TextView textView3, TextView textView4, ImageView imageView) {
textView1.setText(allBean.getTitle());
textView2.setText(allBean.getContext());
textView3.setText(allBean.getDate());
textView4.setText(allBean.getGroup());
}
public void setItemClickListener(CustomItemClickListener listener) {
this.mListener = listener;
}
public void setItemLongClickListener(CustomItemLongClickListener listener) {
this.mLonglistener = listener;
}
}
到此咱们已经把所有的工作都基本完成了,接下来就是填充数据了,基本上跟ListView是一样的,不一样的就是需要设置布局管理器,也就是所谓的是实习ListView还是GridView
Activity/Fragment需实现 CustomItemClickListener
,CustomItemLongClickListener
接口
下面是我项目中的使用
AllFragment.java
/**
* Created by TangRen on 2016-05-28.
*/
public class AllFragment extends Fragment implements CustomItemClickListener, CustomItemLongClickListener, SwipeRefreshLayout.OnRefreshListener {
private View rootView;//缓存Fragment'
private RecyclerView mListView;
private SwipeRefreshLayout mRefresh;
private AllRecycleAdapter mAdapter;
private List<AllBean> list = new ArrayList<AllBean>();
boolean isLoading;
private int count = 20;
private int fist = 0;
private Handler handler = new Handler();
private CustomDiglog mDialog;
private CustomAddDialog addDialog;
private FloatingActionButton fab;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(R.layout.content_main, null);
Log.i("rootView", "rootView==null");
initView();
initData();
}
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null) {
parent.removeView(rootView);
Log.i("remove", "removeView-------rootView");
}
return rootView;
}
private void initView() {
mListView = (RecyclerView) rootView.findViewById(R.id.base_swipe_list);
mRefresh = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe);
fab = (FloatingActionButton) rootView.findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addDialog = new CustomAddDialog(getActivity());
addDialog.setClickListenter(new CustomAddDialog.ClickListenerInterface() {
@Override
public void mark() {
startActivity(new Intent(getActivity(), MarkDownActivity.class));
addDialog.dismiss();
}
@Override
public void wen() {
startActivity(new Intent(getActivity(), FabTextActivity.class));
addDialog.dismiss();
}
});
addDialog.show();
}
});
mRefresh.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_green_light);
mRefresh.setOnRefreshListener(this);
mRefresh.post(new Runnable() {
@Override
public void run() {
mRefresh.setRefreshing(true);
}
});
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
// mListView.setLayoutManager(new GridLayoutManager(getActivity(),4));
mListView.setLayoutManager(layoutManager);
mListView.setHasFixedSize(true);
mAdapter = new AllRecycleAdapter(getActivity(), list);
mListView.setAdapter(mAdapter);
mAdapter.setItemClickListener(this);
mAdapter.setItemLongClickListener(this);
mListView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
Log.i("test", "StateChanged = " + newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastVisbleItemPostion = layoutManager.findLastVisibleItemPosition();
if (lastVisbleItemPostion + 1 == mAdapter.getItemCount()) {
Log.d("test", "loading executed");
boolean isRefresh = mRefresh.isRefreshing();
if (isRefresh) {
mAdapter.notifyItemRemoved(mAdapter.getItemCount());
return;
}
if (!isLoading) {
isLoading = true;
handler.postDelayed(new Runnable() {
@Override
public void run() {
fist = count;
count = count + 5;
LoadData();
isLoading = false;
}
}, 1000);
}
}
}
});
// ItemTouchHelper.Callback
}
private void initData() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
LoadData();
}
}, 1000);
}
/**
* 测试数据
*/
private void LoadData() {
for (int i = fist; i < count; i++) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String time = format.format(date);
AllBean allBean = new AllBean();
allBean.setTitle("程序猿的读书历程" + i + "!");
allBean.setContext("x语言入门—>x语言应用实践—>x语言高阶编程—>x语言的科学与艺术—>编程之美—>编程之道—>编程之禅—>颈椎病康复指南");
allBean.setGroup("攻城狮");
allBean.setDate(time);
list.add(allBean);
}
mAdapter.notifyDataSetChanged();
mRefresh.setRefreshing(false);
mAdapter.notifyItemRemoved(mAdapter.getItemCount());
}
@Override
public void onItemClick(View view, int postion) {
AllBean bean = list.get(postion);
if (bean != null) {
Snackbar.make(mListView, postion + "", Snackbar.LENGTH_LONG).show();
}
}
@Override
public void onItemLongClick(View view, final int postion) {
AllBean bean = list.get(postion);
mDialog = new CustomDiglog(getActivity());
mDialog.setClickListenter(new CustomDiglog.ClickListenerInterface() {
@Override
public void del() {
Toast.makeText(getActivity(), "del", Toast.LENGTH_SHORT).show();
list.remove(postion);
mAdapter.notifyDataSetChanged();
mDialog.dismiss();
}
@Override
public void edit() {
Toast.makeText(getActivity(), "edit", Toast.LENGTH_SHORT).show();
mDialog.dismiss();
}
@Override
public void exp() {
Toast.makeText(getActivity(), "exp", Toast.LENGTH_SHORT).show();
mDialog.dismiss();
}
@Override
public void copy() {
Toast.makeText(getActivity(), "copy", Toast.LENGTH_SHORT).show();
mDialog.dismiss();
}
@Override
public void share() {
Toast.makeText(getActivity(), "share", Toast.LENGTH_SHORT).show();
mDialog.dismiss();
}
});
mDialog.show();
// if (bean != null) {
// Snackbar.make(mListView, postion + "", Snackbar.LENGTH_LONG).show();
// }
}
@Override
public void onRefresh() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
list.clear();
fist = 0;
count = 20;
LoadData();
}
}, 1000);
}
}