RecyclerView相比于ListView, 在回收重用时更具有灵活性, 也就是低耦合, 并且提供了扩展. 加载多个视图时, 应该多用RecyclerView代替ListView.
那么我们来看看这东西应该怎么用? 比如生成一个瀑布流的视图.
首先我们从一个HelloWorld写起, 看看如何构建一个RecyclerView.
依赖
Gradle配置, 添加RecyclerView库的依赖.
1 |
compile 'com.android.support:recyclerview-v7:+' |
布局
布局文件
1 2 3 4 |
<android.support.v7.widget.RecyclerView android:id="@+id/test_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"/> |
代码
LayoutManager: 管理RecyclerView的结构.
Adapter: 处理每个Item的显示.
ItemDecoration: 添加每个Item的装饰.
ItemAnimator: 负责添加\移除\重排序时的动画效果.
LayoutManager\Adapter是必须, ItemDecoration\ItemAnimator是可选.
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 初始化RecyclerView * * @param recyclerView 主控件 */ private void initRecyclerView(RecyclerView recyclerView) { recyclerView.setHasFixedSize(true); // 设置固定大小 initRecyclerLayoutManager(recyclerView); // 初始化布局 initRecyclerAdapter(recyclerView); // 初始化适配器 initItemDecoration(recyclerView); // 初始化装饰 initItemAnimator(recyclerView); // 初始化动画效果 } |
LayoutManager
管理RecyclerView的布局结构.
1 2 3 4 5 |
private void initRecyclerLayoutManager(RecyclerView recyclerView) { // 错列网格布局 recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL)); } |
提供了多种LayoutManager, 瀑布流使用错列网格布局.
Adapter
适配器, 处理RecyclerView的Item事务.
1 2 3 4 |
private void initRecyclerAdapter(RecyclerView recyclerView) { mAdapter = new MyAdapter(getData()); recyclerView.setAdapter(mAdapter); } |
对于Adapter, 我们需要展开来说, 先看看类.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { private List<DataModel> mDataModels; private List<Integer> mHeights; MyAdapter(List<DataModel> dataModels) { if (dataModels == null) { throw new IllegalArgumentException("DataModel must not be null"); } mDataModels = dataModels; mHeights = new ArrayList<>(); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_recycler_view, parent, false); return new MyViewHolder(itemView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { DataModel dataModel = mDataModels.get(position); // 随机高度, 模拟瀑布效果. if (mHeights.size() <= position) { mHeights.add((int) (100 + Math.random() * 300)); } ViewGroup.LayoutParams lp = holder.getTvLabel().getLayoutParams(); lp.height = mHeights.get(position); holder.getTvLabel().setLayoutParams(lp); holder.getTvLabel().setText(dataModel.getLabel()); holder.getTvDateTime().setText(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) .format(dataModel.getDateTime())); } @Override public int getItemCount() { return mDataModels.size(); } public void addData(int position) { DataModel model = new DataModel(); model.setDateTime(getBeforeDay(new Date(), position)); model.setLabel("No. " + (int) (new Random().nextDouble() * 20.0f)); mDataModels.add(position, model); notifyItemInserted(position); } public void removeData(int position) { mDataModels.remove(position); notifyItemRemoved(position); } /** * 获取日期的前一天 * * @param date 日期 * @param i 偏离 * @return 新的日期 */ private static Date getBeforeDay(Date date, int i) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_YEAR, i * (-1)); return calendar.getTime(); } } |
onCreateViewHolder创建ViewHolder.
onBindViewHolder绑定每一项数据.
getItemCount返回列表长度.
RecyclerView强制使用ViewHolder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class MyViewHolder extends RecyclerView.ViewHolder { private TextView mTvLabel; // 标签 private TextView mTvDateTime; // 日期 public MyViewHolder(View itemView) { super(itemView); mTvLabel |