android开发笔记之RecyclerView

参考资料

1.Android RecyclerView 使用完全解析 体验艺术般的控件
http://blog.csdn.net/lmj623565791/article/details/45059587

2.RecyclerViewItemAnimators
https://github.com/gabrielemariotti/RecyclerViewItemAnimators

说明

最近在给别的部门做项目,发现他们使用了RecyclerView控件,我也就跟着看看此控件是个什么东东。

当我参考鸿洋的博客(参考资料1),一步一步的使用此RecyclerView控件后,发现确实此控件非常强大。RecyclerView是集ListView,GridView的优点,更方便使用者在这二者之间切换,并且还增加瀑布StaggerView的显示方式,动画的效果等等。当你了解她后,你会爱上她的。

我的Demo

第一步:在build.gradle文件中添加dependencies

compile "com.android.support:recyclerview-v7:23.1.1"

第二步:实现一个简单的如listview的界面:

布局文件activity_test_recycler_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_test_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="android.com.debugdemo.TestRecyclerView.TestRecyclerView">

    <Button
        android:id="@+id/switchButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="switch recycler type"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/id_recyclerview"
        android:layout_below="@id/switchButton"
        android:divider="#ffff0000"
        android:dividerHeight="2dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

定义适配器HomeAdapter:

import android.com.debugdemo.R;
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;
import android.content.Context;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;


class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{

    private List<String> mDatas;
    private LayoutInflater mInflater;

    public interface OnItemClickLitener
    {
        void onItemClick(View view, int position);
        void onItemLongClick(View view , int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }


    public HomeAdapter(Context context, List<String> datas)
    {
        mInflater = LayoutInflater.from(context);
        mDatas = datas;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        MyViewHolder holder = new MyViewHolder(mInflater.inflate(
                R.layout.item_home, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        holder.tv.setText(mDatas.get(position));

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    removeData(pos);
                    return false;
                }
            });
        }
    }

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

    public void addData(int position)
    {
        mDatas.add(position, "Insert One");
        notifyItemInserted(position);
    }


    public void removeData(int position)
    {
        mDatas.remove(position);
        notifyItemRemoved(position);
    }

    class MyViewHolder extends ViewHolder
    {
        TextView tv;
        public MyViewHolder(View view)
        {
            super(view);
            tv = (TextView) view.findViewById(R.id.id_num);
        }
    }
}

item的布局文件item_home.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margin="2dp"
              android:background="@drawable/item_bg"
              >

    <TextView
        android:id="@+id/id_num"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:gravity="center"
        android:layout_gravity="center"
        android:text="1" />

</FrameLayout>

然后初始化显示:

    private RecyclerView mRecyclerView;
    private List<String> mDatas;
    private HomeAdapter mHomeAdapter;
    ..................

        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mHomeAdapter = new HomeAdapter(TestRecyclerView.this,mDatas);
        mRecyclerView.setAdapter(mHomeAdapter);

效果如图:
这里写图片描述

扫描二维码关注公众号,回复: 2473537 查看本文章

第二步:显示为GridView样式
如果仅仅是这样,那么我们只会认为RecyclerView控件和ListView一样啊。哈哈,如果当你想将ListView显示的样式改为GridView样式,怎么办呢?是不是要修改许多代码呢?如果我们使用RecyclerView控件显示,那么我们只需要简单的几行代码就可以搞定:

//mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setLayoutManager(new GridLayoutManager(this,6));

效果显示:

这里写图片描述

怎么样,现在是不是觉得此控件的方便之处了。

第四步:介绍一下LayoutManager

上面实现了类似ListView样子的Demo,通过使用其默认的LinearLayoutManager,实现类似GridView样式,我们使用了GridLayoutManager 。

RecyclerView.LayoutManager这是一个抽象类,提供了3个实现类:

LinearLayoutManager 现行管理器,支持横向、纵向。
GridLayoutManager 网格布局管理器
StaggeredGridLayoutManager 瀑布就式布局管理器

第五步:实现StaggeredGridLayoutManager 样式:

适配器StaggeredHomeAdapter类:

import java.util.ArrayList;
import java.util.List;
import android.com.debugdemo.R;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;

class StaggeredHomeAdapter extends
        RecyclerView.Adapter<StaggeredHomeAdapter.MyViewHolder>
{

    private List<String> mDatas;
    private LayoutInflater mInflater;
    private List<Integer> mHeights;

    public interface OnItemClickLitener
    {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickLitener mOnItemClickLitener;

    public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
    {
        this.mOnItemClickLitener = mOnItemClickLitener;
    }

    public StaggeredHomeAdapter(Context context, List<String> datas)
    {
        mInflater = LayoutInflater.from(context);
        mDatas = datas;

        mHeights = new ArrayList<Integer>();
        for (int i = 0; i < mDatas.size(); i++)
        {
            mHeights.add( (int) (100 + Math.random() * 400));
        }
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        MyViewHolder holder = new MyViewHolder(mInflater.inflate(
                R.layout.item_staggered_home, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder holder, final int position)
    {
        LayoutParams lp = holder.tv.getLayoutParams();
        lp.height = mHeights.get(position);

        holder.tv.setLayoutParams(lp);
        holder.tv.setText(mDatas.get(position));

        // 如果设置了回调,则设置点击事件
        if (mOnItemClickLitener != null)
        {
            holder.itemView.setOnClickListener(new OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemClick(holder.itemView, pos);
                }
            });

            holder.itemView.setOnLongClickListener(new OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int pos = holder.getLayoutPosition();
                    mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
                    removeData(pos);
                    return false;
                }
            });
        }
    }

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

    public void addData(int position)
    {
        mDatas.add(position, "Insert One");
        mHeights.add( (int) (100 + Math.random() * 400));
        notifyItemInserted(position);
    }

    public void removeData(int position)
    {
        mDatas.remove(position);
        notifyItemRemoved(position);
    }

    class MyViewHolder extends ViewHolder
    {
        TextView tv;
        public MyViewHolder(View view)
        {
            super(view);
            tv = (TextView) view.findViewById(R.id.id_num);

        }
    }
}

item的布局文件item_staggered_home.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_margin="2dp"
             android:background="@drawable/item_bg"
    >

    <TextView
        android:id="@+id/id_num"
        android:layout_width="100dp"
        android:layout_gravity="center"
        android:layout_height="100dp"
        android:gravity="center"
        android:text="1" />

</FrameLayout>

点击效果item_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true" android:drawable="@color/color_item_press"></item>
    <item android:drawable="@color/color_item_normal"></item>
</selector>

实现方式:

mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
                StaggeredGridLayoutManager.VERTICAL));
mStaggeredHomeAdapter = new StaggeredHomeAdapter(this, mDatas);
mRecyclerView.setAdapter(mStaggeredHomeAdapter);

效果图:
这里写图片描述

怎么样?是不是感觉到了此控件的强大之处了,是不是喜欢上了此控件了。

第六步:实现item增加、删除的动画

一种是非常简单的ItemAnimator:
ItemAnimator也是一个抽象类,系统为我们提供了一种默认的实现类。
借助默认的实现,当Item添加和移除的时候,添加动画效果很简单:

// 设置item动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());

另外一种是RecyclerViewItemAnimators类来实现(参考资料二):
这个实现方法可以参考官网资料:
(1)Add the snapshots repo to your build.gradle

repositories {
    maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
}

(2)Add build dependency

dependencies {
    compile 'com.github.gabrielemariotti.recyclerview:recyclerview-animators:0.3.0-SNAPSHOT@aar'
}

(3)实现动画的方法

//mRecyclerView.setItemAnimator(new SlideInOutLeftItemAnimator(mRecyclerView));
//mRecyclerView.setItemAnimator(new SlideInOutRightItemAnimator(mRecyclerView));
//mRecyclerView.setItemAnimator(new SlideInOutTopItemAnimator(mRecyclerView));
//mRecyclerView.setItemAnimator(new SlideInOutBottomItemAnimator(mRecyclerView));
//mRecyclerView.setItemAnimator(new ScaleInOutItemAnimator(mRecyclerView));
mRecyclerView.setItemAnimator(new SlideScaleInOutRightItemAnimator(mRecyclerView));

(4)错误解决:
我一开始以为用上面的方法就可以,后来发现错了,编译的时候竟然报了一个错误:

E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.animation.AnimatorCompatHelper" 

百度后,解决方法为在build.gradle文件中添加:

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support') {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion '25.3.0'
            }
        }
    }
}

第七步:添加item 的点击和长按事件:

        mHomeAdapter.setOnItemClickLitener(new HomeAdapter.OnItemClickLitener()
        {
            @Override
            public void onItemClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " click", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " long click", Toast.LENGTH_SHORT).show();
            }
        });

        mStaggeredHomeAdapter.setOnItemClickLitener(new StaggeredHomeAdapter.OnItemClickLitener()
        {
            @Override
            public void onItemClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " click", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " long click", Toast.LENGTH_SHORT).show();
            }
        });

第八步:综合例子

界面初始显示一个瀑布式布局,点击Button后在瀑布式布局和GridView布局二个样式来回切换.

具体实现逻辑:

import android.com.debugdemo.R;
import android.support.v7.app.ActionBarActivity;
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.support.v7.widget.StaggeredGridLayoutManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import it.gmariotti.recyclerview.itemanimator.ScaleInOutItemAnimator;
import it.gmariotti.recyclerview.itemanimator.SlideInOutBottomItemAnimator;
import it.gmariotti.recyclerview.itemanimator.SlideInOutLeftItemAnimator;
import it.gmariotti.recyclerview.itemanimator.SlideInOutRightItemAnimator;
import it.gmariotti.recyclerview.itemanimator.SlideInOutTopItemAnimator;
import it.gmariotti.recyclerview.itemanimator.SlideScaleInOutRightItemAnimator;

public class TestRecyclerView extends ActionBarActivity {

    private Button switchButton = null;

    private RecyclerView mRecyclerView;
    private List<String> mDatas;

    private HomeAdapter mHomeAdapter;
    private StaggeredHomeAdapter mStaggeredHomeAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_recycler_view);
        initDate();
        init();
        initClickEvent();
        initItemAnimator();
    }

    private void initDate() {
        mDatas = new ArrayList<String>();
        for (int i = 'A'; i < 'z'; i++)
        {
            mDatas.add("" + (char) i);
        }
    }

    private void init() {
        switchButton = (Button) findViewById(R.id.switchButton);
        switchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                initDate();
                if(mRecyclerView.getAdapter() instanceof HomeAdapter){
                    mStaggeredHomeAdapter = new StaggeredHomeAdapter(TestRecyclerView.this, mDatas);
                    mRecyclerView.setAdapter(mStaggeredHomeAdapter);
                    mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3,
                            StaggeredGridLayoutManager.VERTICAL));
                    mRecyclerView.setAdapter(mStaggeredHomeAdapter);

                }else if(mRecyclerView.getAdapter() instanceof StaggeredHomeAdapter){
                    mHomeAdapter = new HomeAdapter(TestRecyclerView.this,mDatas);
                    //mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
                    //mRecyclerView.setLayoutManager(new GridLayoutManager(this,6));
                    mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
                            StaggeredGridLayoutManager.VERTICAL));
                    //mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
                    //        StaggeredGridLayoutManager.HORIZONTAL));
                    mRecyclerView.setAdapter(mHomeAdapter);
                }
                initClickEvent();
            }
        });

        mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
        //mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        //mRecyclerView.setLayoutManager(new GridLayoutManager(this,6));
        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
                StaggeredGridLayoutManager.VERTICAL));
//        mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
//                StaggeredGridLayoutManager.HORIZONTAL));

        mHomeAdapter = new HomeAdapter(TestRecyclerView.this,mDatas);
        //mRecyclerView.setAdapter(mHomeAdapter);

        mStaggeredHomeAdapter = new StaggeredHomeAdapter(this, mDatas);
        mRecyclerView.setAdapter(mStaggeredHomeAdapter);
//        mRecyclerView.addItemDecoration(new DividerItemDecoration(this,
//                DividerItemDecoration.VERTICAL_LIST));
        //mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this));
    }

    private void initClickEvent() {
        mHomeAdapter.setOnItemClickLitener(new HomeAdapter.OnItemClickLitener()
        {
            @Override
            public void onItemClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " click", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " long click", Toast.LENGTH_SHORT).show();
            }
        });

        mStaggeredHomeAdapter.setOnItemClickLitener(new StaggeredHomeAdapter.OnItemClickLitener()
        {
            @Override
            public void onItemClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " click", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onItemLongClick(View view, int position)
            {
                Toast.makeText(TestRecyclerView.this,
                        position + " long click", Toast.LENGTH_SHORT).show();
            }
        });
    }



    private void initItemAnimator() {
        // 设置item动画
        //mRecyclerView.setItemAnimator(new DefaultItemAnimator());

        //mRecyclerView.setItemAnimator(new SlideInOutLeftItemAnimator(mRecyclerView));
        //mRecyclerView.setItemAnimator(new SlideInOutRightItemAnimator(mRecyclerView));
        //mRecyclerView.setItemAnimator(new SlideInOutTopItemAnimator(mRecyclerView));
        //mRecyclerView.setItemAnimator(new SlideInOutBottomItemAnimator(mRecyclerView));
        //mRecyclerView.setItemAnimator(new ScaleInOutItemAnimator(mRecyclerView));
        mRecyclerView.setItemAnimator(new SlideScaleInOutRightItemAnimator(mRecyclerView));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main_staggered, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch (item.getItemId())
        {
            case R.id.id_action_add:
                if(mRecyclerView.getAdapter() instanceof HomeAdapter){
                    mHomeAdapter.addData(1);
                }else if(mRecyclerView.getAdapter() instanceof StaggeredHomeAdapter){
                    mStaggeredHomeAdapter.addData(1);
                }
                break;
            case R.id.id_action_delete:
                if(mRecyclerView.getAdapter() instanceof HomeAdapter){
                    mHomeAdapter.removeData(1);
                }else if(mRecyclerView.getAdapter() instanceof StaggeredHomeAdapter){
                    mStaggeredHomeAdapter.removeData(1);
                }
                break;
        }
        return true;
    }

}

二个界面显示:
瀑布式布局:

这里写图片描述

GridView布局:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/hfreeman2008/article/details/78902663