Android进阶之路——RecyclerView(一)

  最近工作有了着落,毕业论文中期答辩也结束了,比较清闲,可以有时间对之前学的一些知识做一些总结。
  在去年的谷歌 I/O大会上,谷歌发布了Android5.0,称之为L版本。相对于以前的版本这是一个非常大的进步,而且我十分赞同谷歌的这一做法。不论是开发者还是消费者都从中收益。谷歌开放了两个全新的视图:RecyclerView和GardView。而这篇博客主要介绍的是RecyclerView。

一、概述

  谷歌在是这样描述RecyclerView的:“A flexible view for providing a limited window into a large data set.”大概的意思是:一个用于在有限的窗口中展示大量数据集的控件。这样的功能在之前版本中的ListView和GridView也可以实现。那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢?整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现自己想要的效果。 
  
- 显示的方式,通过布局管理器LayoutManager(默认是垂直的,可以改变为水平的)
- 控制Item间的间隔(可绘制),通过ItemDecoration类来实现
- 控制Item增删的动画,通过ItemAnimator
- 控制点击、长按事件,需要自己来实现
  RecyclerView和ListView一样也实现了复用机制,它不仅可以减少CPU不断inflate View的开销,而且可以节省缓存View的内存开销。
  这里写图片描述

二、基本使用

  RecylerView作为support-library发布出来的,这样我们可以在更低的Android版本上使用这个新视图,首先我们要知道怎样找到这个引用的包,在Android Studio上有以下两种方法:
1. 在Android Studio中打开Android SDK Manager然后更新Extras下的Android Support Library即可。

这里写图片描述

  1. 在项目中的build.gradle文件中添加引用,给出我的项目中的gradle截图

这里写图片描述

  使用一个RecylerView,主要需要以下几步:
  

 //  获取RecyclerView对象
 recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
 //  创建线性布局管理器(默认是垂直方向)
 layoutManager = new LinearLayoutManager(this);
 //  将布局管理器设置为水平方向的
 layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
 //  为RecyclerView指定布局管理对象
 recyclerView.setLayoutManager(layoutManager);
 //  设置Item增加、移除动画
 recyclerView.setItemAnimator(new DefaultItemAnimator());
 //  添加分割线
 recyclerView.addItemDecoration(new MyItemDecoration(this));
 myRecyclerAdapter = new MyRecyclerAdapter();
 //  设置adapter
 recyclerView.setAdapter(myRecyclerAdapter);

  相比较于ListView的代码,ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView和ListView不一样的是,RecyclerView不再负责Item的摆放等显示方面的功能。所有和布局、绘制等方面的工作Google都其拆分成不同的类进行管理。所以开发者可以自定义各种各样满足定制需求的的功能类。
  下面是一些和RecyclerView相关的非常重要的类列表。
  
这里写图片描述

  • Activity
package com.recyclerview;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {
    MyRecyclerAdapter myRecyclerAdapter;
    LinearLayoutManager layoutManager;
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //  获取RecyclerView对象
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        //  创建线性布局管理器(默认是垂直方向)
        layoutManager = new LinearLayoutManager(this);
        //  将布局管理器设置为水平方向的
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        //  为RecyclerView指定布局管理对象
        recyclerView.setLayoutManager(layoutManager);
        //  设置Item增加、移除动画
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        //  添加分割线
        recyclerView.addItemDecoration(new MyItemDecoration(this));
        myRecyclerAdapter = new MyRecyclerAdapter();
        //  设置adapter
        recyclerView.setAdapter(myRecyclerAdapter);

        /**
         * 删除和增加item
         */
        Button addBtn, removeBtn;
        addBtn = (Button) findViewById(R.id.add);
        removeBtn = (Button) findViewById(R.id.remove);
        addBtn.setOnClickListener(this);
        removeBtn.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.add://添加item
                myRecyclerAdapter.addItem(1);
                break;
            case R.id.remove://删除item
                myRecyclerAdapter.removeData(1);
                break;
        }
    }
}
  • Activity布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:scrollbars="horizontal"
        tools:listitem="@layout/list_basic_item"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/add"
            style="@style/button_type"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:text="添加"/>

        <Button
            android:id="@+id/remove"
            style="@style/button_type"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:text="删除"/>
    </LinearLayout>
</LinearLayout>
  • Item的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/ic_launcher"/>

    <TextView
        android:id="@+id/textViewSample"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_gravity="center_horizontal"
        android:fontFamily="sans-serif-light"
        android:textSize="20sp"
        tools:text="Sample text"/>

</LinearLayout>
  • MyItemDecoration是继承RecyclerView.ItemDecoration的一个类
      通过ItemDecoration可以使各个Item在视觉上相互分开,其实和ListView的Divider很像。ItemDecoration并不是RecyclerView必须设置的,开发者可以不设置或者设置多个Decoration。RecyclerView会遍历所有的ItemDecoration并调用各自的绘图方法。
      继承ItemDecoration需要实现以下三个方法:
      public void onDraw(Canvas c,RecyclerView parent,RecyclerView.State state)
      public void getItemOffset(Rect outRect,int itemPosition,RecyclerView parent)
      LayoutManager会调用getItemOffset方法来计算每个Item的Decoration合适的尺寸。
package com.recyclerview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class MyItemDecoration extends RecyclerView.ItemDecoration {
    // 默认分隔条Drawable资源的ID
    private static final int[] ATTRS = {android.R.attr.listDivider};
    // 分隔条Drawable对象
    private Drawable mDivider;

    public MyItemDecoration(Context context) {
        TypedArray a = context.obtainStyledAttributes(ATTRS);
        // 获取系统提供的分隔条Drawable对象
        mDivider = a.getDrawable(0);
        // 回收TypedArray所占用的空间
        a.recycle();
    }

    // 在该方法中绘制了所有列表项之间的分隔条
    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int top = parent.getPaddingTop();
        int bottom = parent.getHeight() - parent.getPaddingBottom();
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
            int left = child.getRight() + layoutParams.rightMargin;
            int right = left + mDivider.getIntrinsicWidth();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}
  • MyRecyclerAdapter是继承 RecyclerView.Adapter的一个类
      Adapter负责扮演两个角色:不仅为底部数据提供支持而且还负责为数据创建合适的视图。Adapter适用在Android很多控件,例如ListView、AutoCompleteTextView等。
      继承RecyclerView.Adapter需要实现以下三个方法:
      public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType)
      public void onBindViewHolder(ViewHolder holder,int position)
      public int getItemCount()
ackage com.recyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Random;

public class MyRecyclerAdapter extends
        RecyclerView.Adapter<MyRecyclerAdapter.ViewHolder> {

    private final ArrayList<MyBean> sampleData = DemoApp.getSampleData(20);

    // 用于创建控件
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parentViewGroup, int i) {
        /**
         * 获得列表项控件(LinearLayer对象)
         *
         * list_basic_item.xml布局文件中只包含一个<LinearLayer>标签,在该标签中包含了一个<TextView>标签
         *
         * item是LinearLayout对象
         */
        View item = LayoutInflater.from(parentViewGroup.getContext()).inflate(
                R.layout.list_basic_item, parentViewGroup, false);


        return new ViewHolder(item);

    }

    // 为控件设置数据
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        //  获取当前item中显示的数据
        final MyBean rowData = sampleData.get(position);

        //  设置要显示的数据
        viewHolder.textViewSample.setText(rowData.getSampleText());
        viewHolder.itemView.setTag(rowData);
    }

    @Override
    public int getItemCount() {

        return sampleData.size();
    }

    //  删除指定的Item
    public void removeData(int position) {
        sampleData.remove(position);
        //  通知RecyclerView控件某个Item已经被删除
        notifyItemRemoved(position);

    }

    //  在指定位置添加一个新的Item
    public void addItem(int positionToAdd) {
        sampleData.add(positionToAdd, new MyBean("lyc " + new Random().nextInt(100)));
        //  通知RecyclerView控件插入了某个Item
        notifyItemInserted(positionToAdd);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        private final TextView textViewSample;

        public ViewHolder(View itemView) {
            super(itemView);

            textViewSample = (TextView) itemView
                    .findViewById(R.id.textViewSample);
        }
    }
}

最后看一下效果图:
这里写图片描述

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值