2015-04-16 09:07 721474人阅读 评论(458) 收藏 举报
 分类:
【Android 5.x】(10) 

版权声明:本文为博主原创文章,未经博主允许不得转载。

 

目录(?)[+]

 

转载请标明出处: 
http://blog.csdn.net/lmj623565791/article/details/45059587; 
本文出自:【张鸿洋的博客】

概述

RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 
据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、GridView。

那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢?整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。

  • 你想要控制其显示的方式,请通过布局管理器LayoutManager
  • 你想要控制Item间的间隔(可绘制),请通过ItemDecoration
  • 你想要控制Item增删的动画,请通过ItemAnimator
  • 你想要控制点击、长按事件,请自己写(擦,这点尼玛。)

基本使用

鉴于我们对于ListView的使用特别的熟悉,对比下RecyclerView的使用代码:

mRecyclerView = findView(R.id.id_recyclerview);
//设置布局管理器
mRecyclerView.setLayoutManager(layout);
//设置adapter
mRecyclerView.setAdapter(adapter)
//设置Item增加、移除动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//添加分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(
getActivity(), DividerItemDecoration.HORIZONTAL_LIST));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

ok,相比较于ListView的代码,ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤,那么为什么会添加这么多的步骤呢?

那么就必须解释下RecyclerView的这个名字了,从它类名上看,RecyclerView代表的意义是,我只管Recycler View,也就是说RecyclerView只管回收与复用View,其他的你可以自己去设置。可以看出其高度的解耦,给予你充分的定制自由(所以你才可以轻松的通过这个控件实现ListView,GirdView,瀑布流等效果)。

Just like ListView

  • Activity
package com.zhy.sample.demo_recyclerview;

import java.util.ArrayList;
import java.util.List; import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; public class HomeActivity extends ActionBarActivity
{ private RecyclerView mRecyclerView;
private List<String> mDatas;
private HomeAdapter mAdapter; @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_recyclerview); initData();
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter = new HomeAdapter()); } protected void initData()
{
mDatas = new ArrayList<String>();
for (int i = 'A'; i < 'z'; i++)
{
mDatas.add("" + (char) i);
}
} class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{ @Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, parent,
false));
return holder;
} @Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
holder.tv.setText(mDatas.get(position));
} @Override
public int getItemCount()
{
return mDatas.size();
} class MyViewHolder extends ViewHolder
{ TextView tv; public MyViewHolder(View view)
{
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • Activity的布局文件
<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" > <android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview"
android:divider="#ffff0000"
android:dividerHeight="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </RelativeLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • Item的布局文件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#44ff0000"
android:layout_height="wrap_content" > <TextView
android:id="@+id/id_num"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="1" />
</FrameLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这么看起来用法与ListView的代码基本一致哈~~ 
看下效果图:

看起来好丑,Item间应该有个分割线,当你去找时,你会发现RecyclerView并没有支持divider这样的属性。那么怎么办,你可以给Item的布局去设置margin,当然了这种方式不够优雅,我们文章开始说了,我们可以自由的去定制它,当然我们的分割线也是可以定制的。

ItemDecoration

我们可以通过该方法添加分割线: 
mRecyclerView.addItemDecoration() 
该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类(我觉得最好能提供几个)。 
该类的源码:

public static abstract class ItemDecoration {

public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
} public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
} public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
} @Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

当我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候,RecyclerView在绘制的时候,去会绘制decorator,即调用该类的onDraw和onDrawOver方法,

  • onDraw方法先于drawChildren
  • onDrawOver在drawChildren之后,一般我们选择复写其中一个即可。
  • getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。

接下来我们看一个RecyclerView.ItemDecoration的实现类,该类很好的实现了RecyclerView添加分割线(当使用LayoutManager为LinearLayoutManager时)。 
该类参考自:DividerItemDecoration


package com.zhy.sample.demo_recyclerview; /*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* limitations under the License.
*/ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.State;
import android.util.Log;
import android.view.View; /**
* This class is from the v7 samples of the Android SDK. It's not by me!
* <p/>
* See the license above for details.
*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
}; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
} public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
} @Override
public void onDraw(Canvas c, RecyclerView parent) {
Log.v("recyclerview - itemdecoration", "onDraw()"); if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
} } public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext());
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
} public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
} @Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

该实现类可以看到通过读取系统主题中的 Android.R.attr.listDivider作为Item间的分割线,并且支持横向和纵向。如果你不清楚它是怎么做到的读取系统的属性用于自身,请参考我的另一篇博文:Android 深入理解Android中的自定义属性

获取到listDivider以后,该属性的值是个Drawable,在getItemOffsets中,outRect去设置了绘制的范围。onDraw中实现了真正的绘制。

我们在原来的代码中添加一句:

mRecyclerView.addItemDecoration(new DividerItemDecoration(this,
DividerItemDecoration.VERTICAL_LIST));
  • 1
  • 2
  • 1
  • 2

ok,现在再运行,就可以看到分割线的效果了。

该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况。那么,使用系统的listDivider有什么好处呢?就是方便我们去随意的改变,该属性我们可以直接声明在:

 <!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:listDivider">@drawable/divider_bg</item>
</style>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

然后自己写个drawable即可,下面我们换一种分隔符:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" > <gradient
android:centerColor="#ff00ff00"
android:endColor="#ff0000ff"
android:startColor="#ffff0000"
android:type="linear" />
<size android:height="4dp"/> </shape>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

现在的样子是:

当然了,你可以根据自己的需求,去随意的绘制,反正是画出来的,随便玩~~

ok,看到这,你可能觉得,这玩意真尼玛麻烦,完全不能比拟的心爱的ListView。那么继续看。

LayoutManager

好了,上面实现了类似ListView样子的Demo,通过使用其默认的LinearLayoutManager。

RecyclerView.LayoutManager吧,这是一个抽象类,好在系统提供了3个实现类:

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

上面我们已经初步体验了下LinearLayoutManager,接下来看GridLayoutManager。

  • GridLayoutManager

我们尝试去实现类似GridView,秒秒钟的事情:

//mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
  • 1
  • 2
  • 1
  • 2

只需要修改LayoutManager即可,还是很nice的。

当然了,改为GridLayoutManager以后,对于分割线,前面的DividerItemDecoration就不适用了,主要是因为它在绘制的时候,比如水平线,针对每个child的取值为:

final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
  • 1
  • 2
  • 1
  • 2

因为每个Item一行,这样是没问题的。而GridLayoutManager时,一行有多个childItem,这样就多次绘制了,并且GridLayoutManager时,Item如果为最后一列(则右边无间隔线)或者为最后一行(底部无分割线)。

针对上述,我们编写了DividerGridItemDecoration

package com.zhy.sample.demo_recyclerview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View; /**
*
* @author zhy
*
*/
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration
{ private static final int[] ATTRS = new int[] { android.R.attr.listDivider };
private Drawable mDivider; public DividerGridItemDecoration(Context context)
{
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
} @Override
public void onDraw(Canvas c, RecyclerView parent, State state)
{ drawHorizontal(c, parent);
drawVertical(c, parent); } private int getSpanCount(RecyclerView parent)
{
// 列数
int spanCount = -1;
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{ spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
spanCount = ((StaggeredGridLayoutManager) layoutManager)
.getSpanCount();
}
return spanCount;
} public void drawHorizontal(Canvas c, RecyclerView parent)
{
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++)
{
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getLeft() - params.leftMargin;
final int right = child.getRight() + params.rightMargin
+ mDivider.getIntrinsicWidth();
final int top = child.getBottom() + params.bottomMargin;
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
} public void drawVertical(Canvas c, RecyclerView parent)
{
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++)
{
final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getTop() - params.topMargin;
final int bottom = child.getBottom() + params.bottomMargin;
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
} private boolean isLastColum(RecyclerView parent, int pos, int spanCount,
int childCount)
{
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
if (orientation == StaggeredGridLayoutManager.VERTICAL)
{
if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边
{
return true;
}
} else
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一列,则不需要绘制右边
return true;
}
}
return false;
} private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,
int childCount)
{
LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager)
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
} else if (layoutManager instanceof StaggeredGridLayoutManager)
{
int orientation = ((StaggeredGridLayoutManager) layoutManager)
.getOrientation();
// StaggeredGridLayoutManager 且纵向滚动
if (orientation == StaggeredGridLayoutManager.VERTICAL)
{
childCount = childCount - childCount % spanCount;
// 如果是最后一行,则不需要绘制底部
if (pos >= childCount)
return true;
} else
// StaggeredGridLayoutManager 且横向滚动
{
// 如果是最后一行,则不需要绘制底部
if ((pos + 1) % spanCount == 0)
{
return true;
}
}
}
return false;
} @Override
public void getItemOffsets(Rect outRect, int itemPosition,
RecyclerView parent)
{
int spanCount = getSpanCount(parent);
int childCount = parent.getAdapter().getItemCount();
if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
} else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边
{
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else
{
outRect.set(0, 0, mDivider.getIntrinsicWidth(),
mDivider.getIntrinsicHeight());
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178

主要在getItemOffsets方法中,去判断如果是最后一行,则不需要绘制底部;如果是最后一列,则不需要绘制右边,整个判断也考虑到了StaggeredGridLayoutManager的横向和纵向,所以稍稍有些复杂。最重要还是去理解,如何绘制什么的不重要。一般如果仅仅是希望有空隙,还是去设置item的margin方便。

最后的效果是:

ok,看到这,你可能还觉得RecyclerView不够强大?

但是如果我们有这么个需求,纵屏的时候显示为ListView,横屏的时候显示两列的GridView,我们RecyclerView可以轻松搞定,而如果使用ListView去实现还是需要点功夫的~~~

当然了,这只是皮毛,下面让你心服口服。

  • StaggeredGridLayoutManager

瀑布流式的布局,其实他可以实现GridLayoutManager一样的功能,仅仅按照下列代码:

// mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL));
  • 1
  • 2
  • 1
  • 2

这两种写法显示的效果是一致的,但是注意StaggeredGridLayoutManager构造的第二个参数传一个orientation,如果传入的是StaggeredGridLayoutManager.VERTICAL代表有多少列;那么传入的如果是StaggeredGridLayoutManager.HORIZONTAL就代表有多少行,比如本例如果改为:

mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4,
StaggeredGridLayoutManager.HORIZONTAL));
  • 1
  • 2
  • 1
  • 2

那么效果为:

可以看到,固定为4行,变成了左右滑动。有一点需要注意,如果是横向的时候,item的宽度需要注意去设置,毕竟横向的宽度没有约束了,应为控件可以横向滚动了。 
如果你需要一样横向滚动的GridView,那么恭喜你。

ok,接下来准备看大招,如果让你去实现个瀑布流,最起码不是那么随意就可以实现的吧?但是,如果使用RecyclerView,分分钟的事。 
那么如何实现?其实你什么都不用做,只要使用StaggeredGridLayoutManager我们就已经实现了,只是上面的item布局我们使用了固定的高度,下面我们仅仅在适配器的onBindViewHolder方法中为我们的item设置个随机的高度(代码就不贴了,最后会给出源码下载地址),看看效果图:

是不是棒棒哒,通过RecyclerView去实现ListView、GridView、瀑布流的效果基本上没有什么区别,而且可以仅仅通过设置不同的LayoutManager即可实现。

还有更nice的地方,就在于item增加、删除的动画也是可配置的。接下来看一下ItemAnimator。

ItemAnimator

ItemAnimator也是一个抽象类,好在系统为我们提供了一种默认的实现类,期待系统多 
添加些默认的实现。

借助默认的实现,当Item添加和移除的时候,添加动画效果很简单:

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

系统为我们提供了一个默认的实现,我们为我们的瀑布流添加以上一行代码,效果为:

如果是GridLayoutManager呢?动画效果为:

注意,这里更新数据集不是用adapter.notifyDataSetChanged()而是 
notifyItemInserted(position)notifyItemRemoved(position) 
否则没有动画效果。 
上述为adapter中添加了两个方法:

public void addData(int position) {
mDatas.add(position, "Insert One");
notifyItemInserted(position);
} public void removeData(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Activity中点击MenuItem触发:

    @Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
} @Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.id_action_add:
mAdapter.addData(1);
break;
case R.id.id_action_delete:
mAdapter.removeData(1);
break;
}
return true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

好了,到这我对这个控件已经不是一般的喜欢了~~~

当然了只提供了一种动画,那么我们肯定可以去自定义各种nice的动画效果。 
高兴的是,github上已经有很多类似的项目了,这里我们直接引用下:RecyclerViewItemAnimators,大家自己下载查看。 
提供了SlideInOutLeftItemAnimator,SlideInOutRightItemAnimator
SlideInOutTopItemAnimator,SlideInOutBottomItemAnimator等动画效果。

Click and LongClick

不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。 
不过我们也可以自己去添加,只是会多了些代码而已。 
实现的方式比较多,你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势, 
当然你也可以通过adapter中自己去提供回调,这里我们选择后者,前者的方式,大家有兴趣自己去实现。

那么代码也比较简单:

class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{ //...
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;
} @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);
return false;
}
});
}
}
//...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

adapter中自己定义了个接口,然后在onBindViewHolder中去为holder.itemView去设置相应 
的监听最后回调我们设置的监听。

最后别忘了给item添加一个drawable:

<?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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Activity中去设置监听:


mAdapter.setOnItemClickLitener(new OnItemClickLitener()
{ @Override
public void onItemClick(View view, int position)
{
Toast.makeText(HomeActivity.this, position + " click",
Toast.LENGTH_SHORT).show();
} @Override
public void onItemLongClick(View view, int position)
{
Toast.makeText(HomeActivity.this, position + " long click",
Toast.LENGTH_SHORT).show();
mAdapter.removeData(position);
}
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

测试效果:

ok,到此我们基本介绍了RecylerView常见用法,包含了:

  • 系统提供了几种LayoutManager的使用;
  • 如何通过自定义ItemDecoration去设置分割线,或者一些你想作为分隔的drawable,注意这里 
    巧妙的使用了系统的listDivider属性,你可以尝试添加使用divider和dividerHeight属性。
  • 如何使用ItemAnimator为RecylerView去添加Item移除、添加的动画效果。
  • 介绍了如何添加ItemClickListener与ItemLongClickListener。

可以看到RecyclerView可以实现:

整个体验下来,感觉这种插拔式的设计太棒了,如果系统再能提供一些常用的分隔符,多添加些动画效果就更好了。

通过简单改变下LayoutManager,就可以产生不同的效果,那么我们可以根据手机屏幕的宽度去动态设置LayoutManager,屏幕宽度一般的,显示为ListView;宽度稍大的显示两列的GridView或者瀑布流(或者横纵屏幕切换时变化,有点意思~);显示的列数和宽度成正比。甚至某些特殊屏幕,让其横向滑动~~再选择一个nice的动画效果,相信这种插件式的编码体验一定会让你迅速爱上RecyclerView。

参考资料

Android 自定义RecyclerView 实现真正的Gallery效果

A First Glance at Android’s RecyclerView

https://github.com/gabrielemariotti/RecyclerViewItemAnimators

DividerItemDecoration

群号:423372824 
源码下载 
微信公众号:hongyangAndroid 
(欢迎关注,第一时间推送博文信息) 

 
625

42
 
  相关文章推荐
 
查看评论
61楼 MotherF88ker2017-07-19 15:26发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
60楼 MotherF88ker2017-07-19 15:24发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
59楼 MotherF88ker2017-07-19 15:24发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
58楼 MotherF88ker2017-07-19 15:23发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
57楼 MotherF88ker2017-07-19 15:22发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
56楼 MotherF88ker2017-07-19 15:21发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
55楼 MotherF88ker2017-07-19 15:21发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
54楼 MotherF88ker2017-07-19 15:19发表  [回复]
我遇到个这样的问题:在RecyclerView上有多个item 并且都有各自的监听事件,但是如果两个或多个手指同时点击两个或多个item 就会同时触发多个监听事件.... 请问大神如何避免这种情况呢?
53楼 birdlovestudy2017-07-09 11:27发表  [回复]
垂直recycleview嵌套水平recycleview,水平recycleview 在数据不断增加的同时,水平间距会成倍增长。。请问这是什么原因
52楼 birdlovestudy2017-07-09 11:26发表  [回复]
垂直recycleview嵌套水平recycleview,水平recycleview 在数据不断增加的同时,水平间距会成倍增长。。请问这是什么原因?
51楼 淡淡的id2017-07-07 20:14发表  [回复]
gridlayout的时候没有出现分割线的问题,原因divider_bg.xml中的形状只有高度(height)没有宽度(width)
,所以这个drawable只是提供属性,不用上他的形状,我是这么写 的:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!--divider_bg.xml-->
  3. <shape xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:shape="rectangle" >
  5. <solid android:color="@color/diver_color"/>
  6. <size android:height="0.5dp" android:width="0.5dp"/>
  7. </shape>

提供宽高就行了,宽高不一定要相同,自己调整好看即可

Re: l6512033034天前 11:44发表  [回复]
回复淡淡的id:666 我说怎么没竖分割呢
50楼 Kangkangking2017-07-06 11:42发表  [回复]
Android 深入理解Android中的自定义属性 链接错了 会跳到 Android 自定义RecyclerView 实现真正的Gallery效果
Re: MrZhang_happy2017-08-07 13:45发表  [回复]
回复Kangkangking:正确的地址是哪?
49楼 gqn9647640232017-06-17 11:04发表  [回复]
添加删除条目时,向下滚动程序会崩溃,不知道怎么解决
48楼 小小米乐2017-06-14 17:31发表  [回复]
大神,请问RecycleListView跟recycleview一样么?
47楼 Mark__Liu2017-06-08 16:42发表  [回复]
大神的文章写的很好,但网格布局的ItemDecoration 是有问题的,写了一篇修正方案,望与君共勉
修正方案:http://www.jianshu.com/p/df4430c2a4a8
误处分析
1、一个spanCount列的列表,加上divider后,一行Item减少的宽度为 (divider.size*spanCount-1)
2、而代码中把这一行所减少的宽度平摊在0 - (spanCount-2)位置的Item上,最后一列未做减少,故导致最后一列Item变大
Re: jacksonrickqml2017-07-04 18:08发表  [回复]
回复Mark__Liu:你的分析是对的,可以直接在大神的code上修改:
getItemOffsets方法:
int column=itemPosition%spanCount;
int right= mDivider.getIntrinsicWidth()-(column+1)*mDivider.getIntrinsicWidth()/spanCount;
这样修改后每一行元素的宽度是相同的,可以再drawVertical方法中打log看left,right数据差值
Re: jacksonrickqml2017-07-04 18:07发表  [回复]
回复Mark__Liu:你的分析是对的,可以直接在大神的code上修改:
getItemOffsets方法:
int column=itemPosition%spanCount;
int right= mDivider.getIntrinsicWidth()-(column+1)*mDivider.getIntrinsicWidth()/spanCount;
这样修改后每一行元素的宽度是相同的,可以再drawVertical方法中打log看left,right数据差值
Re: jacksonrickqml2017-07-04 18:05发表  [回复]
回复Mark__Liu:你的分析是对的,可以直接在大神的code上修改:
getItemOffsets方法:
int column=itemPosition%spanCount;
int right= mDivider.getIntrinsicWidth()-(column+1)*mDivider.getIntrinsicWidth()/spanCount;
这样修改后每一行元素的宽度是相同的,可以再drawVertical方法中打log看left,right数据差值
46楼 花-开-花-谢2017-06-04 23:23发表  [回复]
下载的源码运行 最后一行底部还有分割线
45楼 Amandu19952017-06-01 15:04发表  [回复]
献上膝盖
44楼 ahao19855072017-05-31 16:15发表  [回复]
DividerGridItemDecoration 把divider的width设置大些。recyclerview设为两列,就发现左边的item加上divider的宽度等于右边的item的宽度,两个item宽度不一致,这么久了没有人发现吗
Re: z6736717372017-06-01 15:34发表  [回复]
回复ahao1985507:发现了,最后一列没有绘制的时候,左边item的宽度小于右边item的宽度
Re: github_372136712017-06-06 14:25发表  [回复]
回复z673671737:你解决了吗
Re: Mark__Liu2017-06-08 16:45发表  [回复]
回复github_37213671:修正方案:http://www.jianshu.com/p/df4430c2a4a8
43楼 老夫cxd2017-05-26 09:43发表  [回复]
有一个场景,一个app中有3个recyclerview,每一个的间隔线都不相同,按照这种方式的话,只能修改
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:listDivider">@drawable/divider_bg</item>  
</style>
中@drawable/divider_bg的布局文件,也就是只能修改一个。我想知道怎么能修改3
Re: 缺zc2017-07-16 16:31发表  [回复]
回复老夫cxd:分割线直接修改mDivider就行,没必要设置Style
Re: only_thunder2017-06-04 14:32发表  [回复]
回复老夫cxd:如果是我的话,我会考虑重写ItemDecoration类,自己画不同的分割线
42楼 老夫cxd2017-05-26 09:42发表  [回复]
有一个场景,一个app中有3个recyclerview,每一个的间隔线都不相同,按照这种方式的话,只能修改
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:listDivider">@drawable/divider_bg</item>  
</style>
中@drawable/divider_bg的布局文件,也就是只能修改一个。我想知道怎么能修改3
41楼 老夫cxd2017-05-26 09:40发表  [回复]
有一个场景,一个app中有3个recyclerview,每一个的间隔线都不相同,按照这种方式的话,只能修改
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:listDivider">@drawable/divider_bg</item>  
</style>
中@drawable/divider_bg的布局文件,也就是只能修改一个。我想知道怎么能修改3
40楼 colorizedpanda2017-05-25 23:10发表  [回复]
mDivider.setBounds(left, top, right, bottom);
Log.i("TAG==========","left:"+left+",top:"+top+",right:"+right+",bottom:"+bottom);
打印的结果是这样:
TAG==========: left:1081,top:0,right:1080,bottom:1692
TAG==========: left:1081,top:0,right:1080,bottom:1692
,我想问为什么会出现mDivider.getIntrinsicWidth()=-1的现象
39楼 qq_279419812017-05-25 17:04发表  [回复]
牛 逼 啊
38楼 colorizedpanda2017-05-14 18:20发表  [回复]
为什么我的gridview的只显示了行间的divider,列间的不显示
Re: 老夫cxd2017-05-25 16:49发表  [回复]
自定义画线的那个类(DividerItemDecoration)中,画横线的方法中new 出来的recyclerview没用到?
Re: colorizedpanda2017-05-25 22:58发表  [回复]
回复老夫cxd:不是的我说的是gridview自然不是用的这个分割线,我用的是DividerGrideItemDecoration,不过横向的listview效果是用的DividerItemDecoration,同样没有分割线而且高度我也有设置,我打印了一下是因为mDivider.getIntrinsicWidth()=-1
Re: qq_346157682017-05-18 17:37发表  [回复]
回复colorizedpanda:可能是你divider.xml文件 只设置了width 没有设置height
Re: colorizedpanda2017-05-25 23:12发表  [回复]
回复qq_34615768:我根本就没有写过divider.xml这个文件宽和高我都是在drawHorizontal()方法里计算出的
37楼 星光下的微笑2017-05-10 16:23发表  [回复]
自定义了一个简单的layout作为item,但是只有最后一行和最后一列的item正确填充 是怎么回事
36楼 mql4935367752017-05-08 09:30发表  [回复]
怎么少了个文件啊叫libary_zhy_base
Re: 普法居士2017-05-09 13:42发表  [回复]
回复mql493536775:删除Demo_recyclerview_blog目录下的project.properties中的最后两行,然后再用AndroidStudio导入就行了
35楼 元古宙新手2017-05-01 16:37发表  [回复]
虽然很久了,但是还是有个问题,我用的是Grid的Divider,然后分割显示没有问题,我搭debug调试,发现onDraw方法持续被调用,getItemOffsets却没有,这是为什么
34楼 qq_285138612017-04-20 10:44发表  [回复]
为什么网格分割线的竖线不显示?我已经在dvider_bg.xml中添加了width="4dp"了。也尝试过自己再写一个xml。但是再写的那个xml要放在哪里?我的divider_bg.xml加载到<AppTheme>里面去,但是新建的xml放在<AppTheme>会报错。谁可以指导一下?
33楼 qq_285138612017-04-20 10:43发表  [回复]
为什么网格分割线的竖线不显示?我已经在dvider_bg.xml中添加了width="4dp"了。也尝试过自己再写一个xml。但是再写的那个xml要放在哪里?我的divider_bg.xml加载到<AppTheme>里面去,但是新建的xml放在<AppTheme>会报错。谁可以指导一下?
32楼 qq_277487672017-04-19 11:08发表  [回复]
public interface OnItemClickLitener 
Android studio 里会标红 Inner classer cannot have static declarations
Re: XRonaldinho106天前 15:30发表  [回复]
回复qq_27748767:解决了吗?我也是这个问题
Re: loveliwe2017-04-24 15:47发表  [回复]
回复qq_27748767:大神,怎么解决的
Re: Mr--liu2017-05-21 21:09发表  [回复]
回复loveliwe:把内部类变成static
Re: XRonaldinho106天前 15:54发表  [回复]
回复Mr--liu:不是很懂,能详细解答吗,
31楼 qq_353329952017-04-10 15:03发表  [回复]
判断是否是最后一行的逻辑有误。如果刚好填满最后一行时会判定为不是最后一行。修改为
if(childCount % spanCount == 0){
childCount=childCount-spanCount;
}else{
childCount = childCount - childCount % spanCount;
}
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
个人见解,有误勿怪
Re: qq_346157682017-05-18 17:46发表  [回复]
回复qq_35332995:刚发现 是的呢
30楼 supersummerdad2017-03-28 16:25发表  [回复]
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:listDivider">@drawable/divider_bg</item>  
</style>
为什么在可以直接这样设置呢,获取的不是attr.xml里的属性吗,求大神指点下
Re: 勇朝陈2017-03-31 10:25发表  [回复]
回复supersummerdad:因为他用的是android.R.attr.xxx 。 在R前面多了个“android.” 代表用的是系统attr
29楼 shability_X2017-03-24 10:35发表  [回复]
帮助很大,想知道recycleView的刷新功能楼主更新吗?
这个好难感觉。
28楼 chongbin0072017-03-24 10:30发表  [回复]
27楼 shability_X2017-03-19 22:45发表  [回复]
大神,在条目点击监听的时候有个问题
public interface OnItemClickLitener {
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
这一段报红,提示:Make'HomeAdapter'static
但是如果HomeAdapter是static,
在onCreateViewHolder的时候,HomeActivity.this 报红
提示 Make' HomeAdapter' not static 
这样反复……如果把HomeAdapter抽出来作为单独累,数组怎么传递进去呢?
Re: loveliwe2017-04-24 15:55发表  [回复]
回复shability_X:大神,最后怎么解决的
Re: 天使的黑白2017-03-21 18:10发表  [回复]
回复shability_X:viewGroup.getContext()
26楼 岳锋2017-03-15 11:19发表  [回复]
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, parent,
false));

这一行有问题,导致只显示一行,应该改成这样:
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, null,
false));

Re: sjsnwks2017-03-31 17:19发表  [回复]
回复岳锋:是因为Item布局文件最外层布局高度用了match_parent的原因。
25楼 liao_hb2017-03-12 13:06发表  [回复]
我最想问的是StaggeredGridLayoutManager.HORIZONTAL或者StaggeredGridLayoutManager.VERTICAL再结合DividerGridItemDecoration时的分割线怎么搞,这是关键点
24楼 SerBad2017-03-10 16:13发表  [回复]
如果既是最后一行也是最后一列的话,上面就会有错的。改成

outRect.set(0, 0, isLastColum ? 0 : mDivider.getIntrinsicWidth(), isLastRaw ? 0 : mDivider.getIntrinsicHeight());

就好了

23楼 LouisZhoun2017-03-08 16:31发表  [回复]
大神,我想实现动画移动没有闪的空白怎么处理啊
22楼 liqi09992017-03-06 15:14发表  [回复]
libary_zhy_base这个依赖包在哪里
21楼 liqi09992017-03-06 15:11发表  [回复]
libary_zhy_ba这个依赖包在哪?
Re: 大爱皮皮虾2017-03-20 16:16发表  [回复]
回复liqi0999:上Github上找吧
20楼 qq_350008672017-02-23 10:42发表  [回复]
你把嵌套的那个rec以及他的根布局高度都写成包裹
19楼 suyimin20102017-02-21 14:17发表  [回复]
https://github.com/suyimin/RecyclerViewDemo
18楼 陌上丿花已开2017-02-17 13:54发表  [回复]
资源似乎下载不了了
Re: suyimin20102017-02-21 14:17发表  [回复]
回复陌上丿花已开:https://github.com/suyimin/RecyclerViewDemo
17楼 oi0l0io2017-02-06 10:30发表  [回复]
谢谢大大分享 RecyclerView出了很旧 一直没有去学习...
16楼 maiyuqiang2017-01-13 17:05发表  [回复]
这个不需要setTag来缓存view吗
15楼 堕落方能自由2017-01-13 15:19发表  [回复]
RecyclerView嵌套RecyclerView(垂直的listview),子RecyclerView怎么做到随着里面item的个数自适应高度啊,弄了半天还是不行啊?
14楼 桂林的小河2017-01-12 17:43发表  [回复]
和recyclerView相关的,绝对可以减少70%开发时间 http://www.jianshu.com/p/3dfc44155bcf
13楼 在沉默中奋起2017-01-12 15:30发表  [回复]
if (layoutManager instanceof GridLayoutManager)
{
childCount = childCount - childCount % spanCount;
if (pos >= childCount)// 如果是最后一行,则不需要绘制底部
return true;
}这个判断有问题,这样写,如果GridLayout为HORIZONTAL时,最后一行列之间就没有垂直的分割线,需要改成 RecyclerView.LayoutManager lm=parent.getLayoutManager();
if (lm instanceof GridLayoutManager){
int orientation=((GridLayoutManager) lm).getOrientation();
if (orientation==GridLayoutManager.VERTICAL){
if((pos+1)%spanCount==0){// 如果是最后一列,则不需要绘制右边
return true;
}
}else{
childCount=childCount-childCount%spanCount;
if (pos>=childCount){//如果是最后一行不需要绘制下边
return true;
}
}
12楼 羲丶和2017-01-09 15:29发表  [回复]
本人菜鸟,还是不会绘制自定义的图片和颜色分隔线,貌似少了点东西
11楼 zc_fitting2016-12-26 21:17发表  [回复]
瀑布流最左边的分割线怎么去掉
10楼 rellay_my2016-12-21 14:32发表  [回复]
为啥我弄成瀑布流,有的竖线显示,有的竖线不显示呀
Re: 爱吉2017-02-22 16:30发表  [回复]
回复rellay_my:注意他的布局 android:layout_margin=5dp
9楼 treasure_ctw2016-12-20 17:15发表  [回复]
有两个问题问一下:
第一个 drawHorizontal和drawVertical两个方法,变量为什么用final修饰

第二个 我是按照您的代码重写了一遍,为什么我这里的 第一个item 的高度 + 分割线的高度 == 普通item的高度(这就导致了一个问题 就是在最后一个item下边还画了一根线,线下边 有等同分割线高度的空白区域)

Re: treasure_ctw2016-12-20 17:16发表  [回复]
有人能帮忙解答一下吗
Re: UnderEmperor2017-01-16 14:36发表  [回复]
回复treasure_ctw:不用final也没毛病
8楼 Novpusite2016-12-19 09:32发表  [回复]
DividerGridItemDecoration 我复制了这个类,但是竖线不是用到自定义的,好像是默认的,
怎么在可以横竖都用同一条分割线呢、
7楼 reallyxx2016-12-18 16:29发表  [回复]
GridLayoutManager下使用会有点问题,就自己参照着写了一个https://github.com/happyjosh/XXXRecyclerViewDivider,并支持了跨行
6楼 小石G2016-12-17 16:23发表  [回复]
引用“dipolar”的评论:new StaggeredGridLayoutManager(2, Staggered...
搞定 ,必须得加个itemDecoration
5楼 小石G2016-12-17 15:09发表  [回复]
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));的情景下,有么有让item宽度match_parent,高度wrap_content,我试了一下,有个问题,每次第一次加载数据时,两个数据会在同一列,reload一次才会正常,设定了item height第一次loaddata就会正常。
4楼 u0102893842016-12-09 11:01发表  [回复]
好东西呢!
3楼 天意博文2016-12-08 23:52发表  [回复]
好玩的Android小站:http://www.haotianyi.win/
2楼 Tony__sama2016-12-05 11:42发表  [回复]
大神 问个问题,用ripple 标签给recycleView 的item加水波纹点击效果,为什么在item背景设为透明的时候没有效果
Re: Aran_biubiu2016-12-09 16:41发表  [回复]
回复Tony__sama:因为水波纹的效果是要设置background="?android:attr/selectiItexxxx"才管用,你设置backgound的话会将这个给顶替掉
1楼 qq_355965242016-12-03 21:25发表  [回复]
怎么我下载导入eclipse少一个依赖包呢 谁发给我下 谢谢 刚学
 
查看更多评论
您还没有登录,请[登录][注册]
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
 
 
 
 
 

(转载) Android RecyclerView 使用完全解析 体验艺术般的控件的更多相关文章

  1. 【转载】Android RecyclerView 使用完全解析 体验艺术般的控件

    崇拜下鸿洋大神,原文地址:http://blog.csdn.net/lmj623565791/article/details/45059587 概述 RecyclerView出现已经有一段时间了,相信 ...

  2. Android RecyclerView 使用完全解析 体验艺术般的控件

    概述 RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用. 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我 ...

  3. 转载:Android RecyclerView 使用完全解析 体验艺术般的控件

    转自:https://blog.csdn.net/lmj623565791/article/details/45059587

  4. ANDROID L——Material Design详解(UI控件)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Android L: Google已经确认Android L就是Android Lolli ...

  5. Android 打造完美的侧滑菜单/侧滑View控件

    概述 Android 打造完美的侧滑菜单/侧滑View控件,完全自定义实现,支持左右两个方向弹出,代码高度简洁流畅,兼容性高,控件实用方便. 详细 代码下载:http://www.demodashi. ...

  6. Android判断Touch为滑动事件还是操作控件

    Android判断Touch为滑动事件还是操作控件 因为在项目中要判断WebView是否处于滚动状态,但它不像ListView有onScrollStateChanged方法来监听,要实现就得手动监听它 ...

  7. Android学习笔记(九)——布局和控件的自定义

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! View是 Android中一种最基本的 UI组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件 ...

  8. 怎样在Android实现桌面清理内存简单Widget小控件

    怎样在Android实现桌面清理内存简单Widget小控件 我们常常会看到类似于360.金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一 ...

  9. Android 自定义支持快速搜索筛选的选择控件(一)

    Android 自定义支持快速搜索筛选的选择控件 项目中遇到选择控件选项过多,需要快速查找匹配的情况. 做了简单的Demo,效果图如下: 源码地址:https://github.com/whieenz ...

随机推荐

  1. Response.Redirect(),Server.Transfer(),Server.Execute()的区别与网站优化

    转 http://blog.csdn.net/dannywj1371/article/details/10213631 1.Response.Redirect():Response.Redirect方 ...

  2. Centos下MongoDB数据库的安装以及配置开机自启动(三)

    最近写了一个用node来操作MongoDB完成增.删.改.查.排序.分页功能的示例,并且已经放在了服务器上地址:http://39.105.32.180:3333. 在服务器上完全可以用yum来安装管 ...

  3. hadoop配置历史服务器

    此文档不建议当教程,仅供参考 配置历史服务器 我是在hadoop1机器上配置的 配置mapred-site.xml <property> <name>mapreduce.job ...

  4. quartz定时任务框架调度机制解析

    转自集群调度机制调研及源码分析 quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 qurat ...

  5. Golden Gate 概述

    概述: 是什么?Oracle GoldenGate 提供异构环境间事务数据的实时.低影响的捕获.路由.转换和交付. 非侵入: 不建触发器,不建中间表,无需增量标记或时间戳字段 不在源表上进行数据查询 ...

  6. USB接口

     总结: 1.电脑的usb接口是usb母接口,u盘接口是usb公接口 2.usb otg指的是不需要电脑作为中转站接口,例如如果买一个micro 转otg接口即可将手机直接接u盘 3.方形usb口是u ...

  7. Unity类继承关系 图

    UnityEngine(命名空间) 其他命名空间 其他类 Object(类) 其他类(继承自Object) Component(类)(继承自Object) 其他类(继承自Component) Tran ...

  8. day09-2 字典,集合的内置方法

    目录 字典的内置方法 作用 定义方式 方法 优先掌握 需要掌握 存储一个值or多个值 有序or无序 可变or不可变 集合的内置方法 作用 定义方式 方法 存储一个值or多个值 有序or无序 可变or不 ...

  9. mySql 使用 SQL 文件脚本 failed to open file 注意事项

    1.路径不要有中文,其实最好是全英文 2.路径可以有空格 3.路径两头不要加引号 4.作为一个MySQL命令,source C:/lib/a.sql; 后边的分号是要的. 5.使用 unix 路径风格 ...

  10. Ubuntu_18.04安装网易云音乐

    首先到网易云音乐官网下载网易云音乐,ubuntu版的,安装. 这时候的图标打不开,缺少libcanberra sudo apt install libcanberra-gtk-module 安装完了配 ...