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的显示方式,动画的效果等等。当你了解她后,你会爱上她的。
第一步:在build.gradle文件中添加dependencies
compile "com.android.support:recyclerview-v7:23.1.1"
第二步:实现一个简单的如listview的界面:
布局文件activity_test_recycler_view.xml:
<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
{
private List 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 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:
<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);
第二步:显示为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
{
private List mDatas;
private LayoutInflater mInflater;
private List 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 datas)
{
mInflater = LayoutInflater.from(context);
mDatas = datas;
mHeights = new ArrayList();
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:
<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
<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 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();
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;
}
}
二个界面显示:
瀑布式布局: