Android RecyclerView使用详解

RecyclerViwe与ListView对比

ListView不足
  1. 运行效率差,不使用ViewHolder等技巧,性能会很差。
  2. 扩展性差,子布局效果完全一致。
  3. 无法实现横向滚动,水平列表。
RecyclerViwe优点
  1. 增强版ListView,优化了ListView的不足
  2. 可轻松实现ListView的效果,扩展性强,子布局可根据自身情况变化。
  3. 可实现水平,瀑布流等列表样式。
  4. Android官方推荐使用RecycleViwe,未来RecycleViwe将替代ListView。
  5. RecyclerView的布局样式完全是一个白板,甚至没有分隔线,完全由个人设计没添加组件。

Demo效果图

废话不多说,先上几张效果图。
点击水平列表的图片,会显示Toast;点击列表其他地方会跳转到瀑布流界面。


本文导读

  1. RecyclerViwe基本用法,使用流程
  2. RecyclerViwe实现水平列表
  3. RecyclerViwe实现瀑布流列表
  4. RecyclerViwe的点击事件

RecycleViwe基本用法

添加依赖
dependencies {
    ...
     compile 'com.android.support:recyclerview-v7:25.3.1'
    ...
}
xml主界面布局

由于RecycleView不在内置的SDK中,需要写出完整的路径包。
主布局中两个RecycleView,上面一个显示垂直列表,下面一个显示水平列表。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycle_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <android.support.v7.widget.RecyclerView
        android:background="@color/colorAccent"
        android:id="@+id/h_view"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:layout_alignParentBottom="true"/>
</RelativeLayout>

Adapter类

  1. 新建一个RecycleAdapter类继承RecyclerView.Adapter,泛型指定为RecycleAdapter.ViewHolder,ViewHolder是RecycleAdapter定义的一个内部类。
  2. 创建类的构造函数,用于传入RecycleView数据源。
  3. 重写onCreateViewHolder(), onBindViewHolder()和getItemCount()方法。
  4. onCreateViewHolder()用于创建ViewHolder实例,将加载的布局传入构造函数中,返回ViewHolder实例。
  5. onBindViewHolder()用于对RecyclerView子项进行复制,会在每个子项滚动到屏幕的时候执行。
  6. getItemCount()用于RecyclerView有多少子项,直接返回数据源的长度即可。
  7. 两个RecyclerView的Adapter类除子布局外基本完全一致。子布局较简单,此处不再展示。如有需要可下载Demo参考。
public class RecycleAdapter extends RecyclerView.Adapter<RecycleAdapter.ViewHolder> {
    private List<Info> list;

    public RecycleAdapter(List<Info> list) {
        this.list = list;
    }

    @Override
    public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_layout, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Info info = list.get(position);
        holder.img.setImageResource(info.getId());
        holder.text.setText(info.getName());

    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.img)
        ImageView img;
        @BindView(R.id.text)
        TextView text;

        public ViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }
}

实现垂直及水平列表

  1. LayoutManager用于指定RecyclerView的布局方式。
  2. 使用LinearLayoutManager代表线性布局,默认是垂直。无法在xml布局中指定,必须使用setLayoutManager()方法设置,如不设置则RecyclerView无法正常显示
  3. 创建Adapter类实例,传入数据源。
  4. setAdapter()完成适配器设置。
public class MainActivity extends AppCompatActivity {
    @BindView(R.id.recycle_view)
    RecyclerView recycleView;
    @BindView(R.id.h_view)
    RecyclerView hView;
    private List<Info> list = new ArrayList<>();
    private RecycleAdapter adapter;
    private HRecycleAdapter hadapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        ButterKnife.bind(this);
        initData();
        initView();


    }

    private void initView() {
        recycleView.setLayoutManager(new LinearLayoutManager(this));//指定列表布局方式,默认是垂直
        adapter = new RecycleAdapter(list);
        recycleView.setAdapter(adapter);

        LinearLayoutManager lm = new LinearLayoutManager(this);
        lm.setOrientation(LinearLayoutManager.HORIZONTAL);
        hView.setLayoutManager(lm);//指定水平列表线性布局
        hadapter = new HRecycleAdapter(list);
        hView.setAdapter(hadapter);
        
    }

    private void initData() {//初始化列表数据
        for (int i = 0; i < 20; i++) {
            Info info = new Info(R.mipmap.ic_launcher_round, "第" + (i + 1) + "条数据");
            list.add(info);
        }
    }

}

以上代码就实现了,RecyclerView的垂直与水平布局。

实现瀑布流布局

  1. 创建一个新的activity显示瀑布流布局。该Actvity的布局中包含一个RecycleView作为瀑布流的父布局。
  2. 适当修改以上两种RecyclerView的xml子布局作为瀑布流的子布局,android:layout_height="wrap_content"必须设置为wrap_content,这样才会根据不同的数据源显示不同的高度,不会固定死子列表的高度。
  3. 瀑布流的Adapter类与上面的Adapter,除修改子布局样式外基本一致。
瀑布流activity代码
  1. StaggeredGridLayoutManager用于设置该RecyclerView的布局为交错网格布局。
  2. StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)有两个参数,指定布局分为3列,StaggeredGridLayoutManager.VERTICAL表示会让布局纵向排列。
  3. randomString(String s)方法,用于随机改变数据源中文字数据的长度,因为数据源不同才会显示出参差交错的效果。
public class WaterfallActivity extends AppCompatActivity {

    @BindView(R.id.waterfall)
    RecyclerView waterfall;
    private WaterfallAdapter adapter;
    private List<Info> list = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_waterfall);
        ButterKnife.bind(this);
        initData();
        StaggeredGridLayoutManager sgm = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
        waterfall.setLayoutManager(sgm);
        adapter = new WaterfallAdapter(list);
        waterfall.setAdapter(adapter);
    }

    private void initData() {
        for (int i = 0; i < 20; i++) {
            Info info = new Info(R.mipmap.ic_launcher_round, randomString("第" + (i + 1) + "条数据"));
            list.add(info);
        }

    }

    private String randomString(String s) {
        Random random = new Random();
        int len = random.nextInt(10) + 1;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            builder.append(s);
        }
        return builder.toString();
    }
}

以上代码实现了瀑布流,只需修改子布局的样式,及设置布局管理器为StaggeredGridLayoutManager即可。

RecyclerView点击事件

不同于ListView的是,RecyclerView没有提高类似setOnItemClickListener()的监听器方法,而是需要我们给子项具体的View去注册点击事件,相比于ListView实现会比较麻烦。
看到前面RecyclerView的多种样式,你肯定会在此大失所望。为什么RecyclerView各方面都优于ListView,偏偏在点击事件上没有处理好呢?
其实不是这样的,ListView在点击事件是处理并不好,比如我们想点击子项具体的某一个按钮呢?虽然ListView也能实现,但是就会很麻烦。为此RecyclerView直接放弃了子项点击事件,所有的事件都有具体的View去注册实现,就没有这个困扰。

我们以实现水平RecyclerView的点击事件为例,修改其对应的Adapter类,实现点击事件。
点击列表中的图片用Toast显示子项的文字信息。点击子列表实现界面跳转。

  1. 在ViewHolder中创建一个View表示整个子项。
  2. onCreateViewHolder()方法中我们holder控制不同的子项组件,实现setOnClickListener()点击注册监听,处理不同的事务。
  3. 使用 holder.getAdapterPosition()获取用户点击的position,然后拿到对应的实例。
  4. 当点击图片时,会触发图片的点击事件。点击文字部分,由于文字没有注册监听,使用会被最外层布局捕获。即子项中注册了点击的,会触发对应的监听事件;没注册点击的,会触发子项监听事件。
public class HRecycleAdapter extends RecyclerView.Adapter<HRecycleAdapter.ViewHolder> {
    private List<Info> list;

    public HRecycleAdapter(List<Info> list) {
        this.list = list;
    }

    @Override
    public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.hrecycle_layout, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.infoView.setOnClickListener(new View.OnClickListener() {//整个子项
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(parent.getContext(), WaterfallActivity.class);
                parent.getContext().startActivity(intent);
            }
        });

        holder.img.setOnClickListener(new View.OnClickListener() {//图片点击
            @Override
            public void onClick(View v) {
                int pos = holder.getAdapterPosition();
                Info info = list.get(pos);
                Toast.makeText(v.getContext(), info.getName(), Toast.LENGTH_SHORT).show();
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Info info = list.get(position);
        holder.img.setImageResource(info.getId());
        holder.text.setText(info.getName());

    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        @BindView(R.id.img)
        ImageView img;
        @BindView(R.id.text)
        TextView text;
        View infoView;

        public ViewHolder(View view) {
            super(view);
            infoView = view;
            ButterKnife.bind(this, view);
        }
    }
}

RecyclerView的强大之处就在可以轻松实现子项中某一控件的点击事件。
至此完成整个Demo。

Demo Moudle代码下载

http://download.csdn.net/detail/demonliuhui/9840902

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值