RecyclerView 最佳入门

翻译自http://www.vogella.com/tutorials/AndroidRecyclerView/article.html

1 在安卓中的列表(List)和网格(Grid)

1.1 在安卓中使用列表和网格

在手机应用中,以列表或者网格的形式展示元素是一个非常重要的模式。用户可以看到条目(item)的集合并且可以滚动他们。这个条目的集合可以是一个列表、一个网格或者是代表数据的其他的结构。就像如下的图片:

这里写图片描述

用户通过触摸时间或者是工具栏和这些条目的集合进行交互。每一个条目都可以被选中。选中这个条目可能会显示详情或者是更新工具栏。如下图:
这里写图片描述

1.2 使用ReclclerView

RecyclerView类就是用来支持显示数据集合的。

这是一个有安卓系统提供的,现在化的ListView和GridView版本。RecyclewView处理了之前空间所存在的问题。它强制了一种编码风格可以让结果有一种好的表现形式。并且它为增加或者删除元素提供了默认的动画。
RecyclerView 允许不同的布局去显示不同的条目。

ReclclerView使用ViewHolder去存储view的引用。 一个ViewHolder类是一个adapter里的静态内部类,维持了不同view的引用。使用这些引用可以省去findViewById()所花费的时间。

1.3 Adapter

一个Adapter负责管理数据模型,并且把它适配到个子的实体。它集成自RecyclerView.Adapter,并且通过RecyclerView.setAdapter方法分配到指定的recycler view。适配器的输入可以是任意的java类,但必须通过getItemCount()返回条目的个数。

适配器为不用的元素填充布局。在onCreateViewHolder 这个方法之后这项活就完成了。每当有一个实体在RecyclerView中可见,这个函数就返回一个ViewHolder 对象。

这个实例被用作访问在被填充的布局中的视图。onCreateViewHolder 方法只有在新的视图必须被创建的时候才会调用。

每一个可见状态的实体都会通过适配器被填入正确的数据模型。一旦数据条目变得课件,适配器就会为刚刚填充的控件指派何时的数据。这项工作由onBindViewHolder 方法完成。

举个例子,一个列表的实体有可能是这样的:嘴边有一个图片,中间由两个文字。比如这样:
这里写图片描述

布局文件

android:contentDescription="TODO"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/secondLine"
        android:layout_width="fill_parent"
        android:layout_height="26dip"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@id/icon"
        android:ellipsize="marquee"
        android:singleLine="true"
        android:text="Description"
        android:textSize="12sp" />

    <TextView
        android:id="@+id/firstLine"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/secondLine"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_alignWithParentIfMissing="true"
        android:layout_toRightOf="@id/icon"
        android:gravity="center_vertical"
        android:text="Example application"
        android:textSize="16sp" />

</RelativeLayout>

1.4 Gradle 依赖

RecyclerView是单独的控件,在API7+中可以使用,在Gradle中加入依赖

dependencies {
    ...
    compile "com.android.support:recyclerview-v7:23.0.1"
}

1.5 默认的布局管理者

layout manager 决定了数据在RecyclerView中如何战术。RecyclerView库提供了如下的manager;

  • LinearLayoutManager 展示了水平或者垂直的滚动列表
  • GridLayoutManager 在网格中展示条目
  • StaggeredGridLayoutManager 在挫列的网格中展示条目

1.6 相关联的类

  • Adapter(必须) 提供数据:为各自的实体创建视图
  • ViewHolder(必须 )维持了所有被数据填充的实体的视图的引用
  • LayoutManager(必须,但默认的实现就可以):同ViewHolder
  • ItemDecoration(默认行为,可以重写):一个实体的周围的装饰
  • ItemAnimator(默认行为可以重写):条目增加删除重新排序所产生动画

1.7 处理点击事件

触摸事件,比如说点击,应该在recycler view中被view处理。如果触发了其他对象(比如说activity或者fragment),你应该通过adapter的构造方法传递进来,这样允许adapter存储对象的引用,然后调用它的方法(回调函数)

1.8 使用不同的布局

adapter需要为每一行条目创建布局,根布局一般是ViewGroup (layout manager),包含了很多view,比如说ImageView 或者TextView,下图是奇偶行显示不同的效果

这里写图片描述

getItemViewType 方法可以让 recycler view 去决定哪一种应该被对象使用。如果这个类型需要的话,框架会子的自动调用onCreateViewHolder 。在 onCreateViewHolder 方法中,你应该填充正确的布局并且返回一个合适的view holder。

1.9 动画

想要自定义动画需要继承RecyclerView.ItemAnimator并且调用RecyclerView.setItemAnimator() 方法,

1.10 过滤和排序

需要在adapter中处理逻辑。

1.11 更新数据

notifyItemInserted(position)在增加一条数据的时候可以通知view去把它加入到何时的位置。

notifyItemRemoved(position)在删除的时候可以通知,

2 练习:一个简单的例子

最终目标
这里写图片描述

布局文件

<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="${relativePackage}.${activityClass}" >

    <!-- A RecyclerView with some commonly used attributes -->

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="12dp"
        android:layout_marginRight="12dp"
        android:elevation="2dp"
        android:src="@drawable/ic_add_circle" />

</RelativeLayout>

提示:ImageView有android:elevation属性,会让安卓画一个阴影,

没一个条目的布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip" >

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_alignParentBottom="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="6dip"
        android:contentDescription="TODO"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/secondLine"
        android:layout_width="fill_parent"
        android:layout_height="26dip"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@id/icon"
        android:ellipsize="marquee"
        android:singleLine="true"
        android:text="Description"
        android:textSize="12sp" />

    <TextView
        android:id="@+id/firstLine"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/secondLine"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_alignWithParentIfMissing="true"
        android:layout_toRightOf="@id/icon"
        android:gravity="center_vertical"
        android:text="Example application"
        android:textSize="16sp" />

</RelativeLayout>

创建如下的类

package com.vogella.android.recyclerview;

import java.util.ArrayList;

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

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
        private ArrayList<String> mDataset;

        // Provide a reference to the views for each data item
        // Complex data items may need more than one view per item, and
        // you provide access to all the views for a data item in a view holder
        public class ViewHolder extends RecyclerView.ViewHolder {
                // each data item is just a string in this case
                public TextView txtHeader;
                public TextView txtFooter;

                public ViewHolder(View v) {
                        super(v);
                        txtHeader = (TextView) v.findViewById(R.id.firstLine);
                        txtFooter = (TextView) v.findViewById(R.id.secondLine);
                }
        }

        public void add(int position, String item) {
                mDataset.add(position, item);
                notifyItemInserted(position);
        }

        public void remove(String item) {
                int position = mDataset.indexOf(item);
                mDataset.remove(position);
                notifyItemRemoved(position);
        }

        // Provide a suitable constructor (depends on the kind of dataset)
        public MyAdapter(ArrayList<String> myDataset) {
                mDataset = myDataset;
        }

        // Create new views (invoked by the layout manager)
        @Override
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                        int viewType) {
                // create a new view
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.rowlayout, parent, false);
                // set the view's size, margins, paddings and layout parameters
                ViewHolder vh = new ViewHolder(v);
                return vh;
        }

        // Replace the contents of a view (invoked by the layout manager)
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
                // - get element from your dataset at this position
                // - replace the contents of the view with that element
                final String name = mDataset.get(position);
                holder.txtHeader.setText(mDataset.get(position));
                holder.txtHeader.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                remove(name);
                        }
                    });

                holder.txtFooter.setText("Footer: " + mDataset.get(position));

        }

        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
                return mDataset.size();
        }

}

Activity

public class MyActivity extends Activity {
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_activity);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);

        // specify an adapter (see also next example)
        mAdapter = new MyAdapter(myDataset);
        mRecyclerView.setAdapter(mAdapter);
    }
    ...
}
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值