12.6 列表与卡片" class="reference-link">12.6 列表与卡片
12.6.1 RecyclerView" class="reference-link">12.6.1 RecyclerView
在Android5.X中将使用了很久的ListView做了升级,增加了一个使用更方便、效率更高的控件——RecyclerView。RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,它同样拥有item回收复用的功能,但是RecyclerView可以直接把ViewHolder的实现封装起来,用户只要实现自己的ViewHolder就可以了,该组件会自动帮你回收复用每一个item。
要使用RecyclerView,首先需要在项目中引入com.android.support:recyclerview- v7:21.0.2的依赖。在布局中使用RecyclerView与使用ListView基本类似,同样需要使用一个类似List item的布局,在Material Design中,通常与CardView配合使用,后面我们会详细讲解CardView的使用方法。
使用RecyclerView的重点与使用ListView一样,需要使用一个合适的数据适配器来加载数据,RecyclerView中需要重写的很多方法都似曾相识,不过RecyclerView更加先进的是,它已经封装好了ViewHolder,只要实现功能就可以了,而使用上仍然是跟在ListView中使用ViewHolder一样,代码如下所示。
- package com.xys.myapplication;
- 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.List;
- public class RecyclerAdapter
- extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
- private List<String> mData;
- public RecyclerAdapter(List<String> data) {
- mData = data;
- }
- public OnItemClickListener itemClickListener;
- public void setOnItemClickListener(
- OnItemClickListener itemClickListener) {
- this.itemClickListener = itemClickListener;
- }
- public interface OnItemClickListener {
- void onItemClick(View view, int position);
- }
- public class ViewHolder extends RecyclerView.ViewHolder
- implements View.OnClickListener {
- public TextView textView;
- public ViewHolder(View itemView) {
- super(itemView);
- textView = (TextView) itemView;
- textView.setOnClickListener(this);
- }
- //通过接口回调来实现RecyclerView的点击事件
- @Override
- public void onClick(View v) {
- if (itemClickListener != null) {
- itemClickListener.onItemClick(v, getPosition());
- }
- }
- }
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
- //将布局转化为View并传递给RecyclerView封装好的ViewHolder
- View v = LayoutInflater.from(viewGroup.getContext()).inflate(
- R.layout.rc_item, viewGroup, false);
- return new ViewHolder(v);
- }
- @Override
- public void onBindViewHolder(ViewHolder viewHolder, int i) {
- //建立起ViewHolder中视图与数据的关联
- viewHolder.textView.setText(mData.get(i) + i);
- }
- @Override
- public int getItemCount() {
- return mData.size();
- }
- }
上面就是一个非常简单却典型的RecyclerView,通过onCreateViewHolder将List item的布局转化为View,并传递给RecyclerView封装好的ViewHolder,就可以将数据与视图关联起来了。但是有一点要注意的是,Android并没有给RecyclerView增进点击事件,所以我们需要自己使用接口回调机制,创建一个点击事件的接口,代码如下所示。
- public OnItemClickListener itemClickListener;
- public void setOnItemClickListener(OnItemClickListener itemClickListener) {
- this.itemClickListener = itemClickListener;
- }
- public interface OnItemClickListener {
- void onItemClick(View view, int position);
- }
类似ListView的List Item视图如下所示。
- <?xml version="1.0" encoding="utf-8"?>
- <TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:textSize="40sp"
- android:gravity="center"
- android:layout_width="match_parent"
- android:background="#bebebe"
- android:layout_margin="3dp"
- android:layout_height="match_parent">
- </TextView>
当然,仅仅是优化性能也是不够的,让开发者能够更加方便地使用也是非常重要的。Google在RecyclerView中定义了LayoutManager来帮助开发者更加方便地创建不同的布局,下面的例子就演示了如何创建简单的水平和竖直两种布局方式。当然,你也可以通过自定义LayoutManager来创建自己的布局,核心代码如下所示。
- mRcList.setLayoutManager(new LinearLayoutManager(RecyclerTest.this));
- mRcList.setLayoutManager(new GridLayoutManager(RecyclerTest.this, 3));
完整代码如下所示。
- package com.xys.myapplication;
- import android.animation.Animator;
- import android.animation.AnimatorListenerAdapter;
- import android.app.Activity;
- import android.os.Bundle;
- import android.support.v7.widget.DefaultItemAnimator;
- import android.support.v7.widget.GridLayoutManager;
- import android.support.v7.widget.LinearLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.Spinner;
- import java.util.ArrayList;
- import java.util.List;
- public class RecyclerTest extends Activity {
- private RecyclerView mRcList;
- private RecyclerAdapter mAdapter;
- private RecyclerView.LayoutManager mLayoutManager;
- private Spinner mSpinner;
- private List<String> mData = new ArrayList<String>();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.recycler);
- mRcList = (RecyclerView) findViewById(R.id.rc_list);
- mLayoutManager = new LinearLayoutManager(this);
- mRcList.setLayoutManager(mLayoutManager);
- mRcList.setHasFixedSize(true);
- //设置显示动画
- mRcList.setItemAnimator(new DefaultItemAnimator());
- mSpinner = (Spinner) findViewById(R.id.spinner);
- mSpinner.setOnItemSelectedListener(
- new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent,
- View view,
- int position,
- long id) {
- if (position == 0) {
- mRcList.setLayoutManager(
- //设置为线性布局
- new LinearLayoutManager(
- RecyclerTest.this));
- } else if (position == 1) {
- mRcList.setLayoutManager(
- //设置为表格布局
- new GridLayoutManager(
- RecyclerTest.this, 3));
- } else if (position == 2) {
- }
- }
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- //增加测试数据
- mData.add("Recycler");
- mData.add("Recycler");
- mData.add("Recycler");
- mAdapter = new RecyclerAdapter(mData);
- mRcList.setAdapter(mAdapter);
- mAdapter.setOnItemClickListener(
- new RecyclerAdapter.OnItemClickListener() {
- @Override
- public void onItemClick(final View view, int position) {
- //设置点击动画
- view.animate()
- .translationZ(15F).setDuration(300)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- view.animate()
- .translationZ(1f)
- .setDuration(500).start();
- }
- }).start();
- }
- });
- }
- public void addRecycler(View view) {
- mData.add("Recycler");
- int position = mData.size();
- if (position > 0) {
- mAdapter.notifyDataSetChanged();
- }
- }
- public void delRecycler(View view) {
- int position = mData.size();
- if (position > 0) {
- mData.remove(position - 1);
- mAdapter.notifyDataSetChanged();
- }
- }
- }
在程序中,使用Spinner来选择线性布局管理器还是表格布局管理器,并给按钮增加了点击动画效果,整个程序运行效果如图12.12、图12.13、图12.14所示,图12.12展示了RecyclerView的线性布局,图12.13、图12.14展示了RecyclerView的表格布局。
![]() | ![]() | ![]() |
| 图12.12 RecyclerView纵向布局 | 图12.13 RecyclerView横向布局 | 图12.14 RecyclerView表格布局 |
12.6.2 CardView" class="reference-link">12.6.2 CardView
CardView曾经开始流行在Google+上,后来越来越多的App也引入了Card这样一种布局方式。因此在Android 5.X上,Google索性就提供了CardView的控件,方便大家使用这种布局。说到底,CardView也是一个容器类布局,只是它提供了卡片这样一种形式。开发者可以定义卡片的大小与视图高度,并设置圆角的角度。不过使用CardView的方式与RecyclerView还是有区别的,首先同样是需要在项目中引入com.android.support:cardview-v7:21.+的依赖。其次在布局文件中使用CardView的时候需要引入一个新的名字空间——在Android Studio中使用xmlns:card_view=http://schemas.android. com/apk/res-auto来添加。这样才可以通过自定义的名字空间来引用它的两个属性。
- card_view:cardBackgroundColor="@color/cardview_background"
- card_view:cardCornerRadius="8dp"
这两个属性非常简单,第一个是设置背景颜色,第二个是设置圆角的角度。我们以一个例子来演示一下CardView的使用,XML代码如下所示。
- <?xml version="1.0" encoding="utf-8"?>
- <android.support.v7.widget.CardView xmlns:android="http://schemas.
- android.com/apk/res/android"
- xmlns:card_view="http://schemas.android.com/apk/res-auto"
- android:id="@+id/cardview"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="40dp"
- card_view:cardBackgroundColor="@color/cardview_initial_background"
- card_view:cardCornerRadius="30dp"
- android:elevation="10dp"
- android:layout_marginLeft="@dimen/margin_large"
- android:layout_marginRight="@dimen/margin_large">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="100dp"
- android:gravity="center"
- android:layout_gravity="center"
- android:textSize="30sp"
- android:layout_margin="@dimen/margin_medium"
- android:text="I am a CardView" />
- </android.support.v7.widget.CardView>
显示效果如图12.15所示。
图12.15 CardView
