RecyclerView实现瀑布流效果(图文详解+源码奉送)

举报
江南一点雨 发表于 2021/08/16 23:51:33 2021/08/16
【摘要】 最近有时间研究了一下RecyclerView,果然功能强大啊,能实现的效果还是比较多的,那么今天给大家介绍一个用RecyclerView实现的瀑布流效果。 先来一张效果图: 看看怎么实现吧: 整体工程目录结构: 这里要特别强调一点,有人可能不知道去哪里找android-support-v7-recyclerview.jar这个文件,其实它就在你下...

最近有时间研究了一下RecyclerView,果然功能强大啊,能实现的效果还是比较多的,那么今天给大家介绍一个用RecyclerView实现的瀑布流效果。

先来一张效果图:


这里写图片描述


看看怎么实现吧:
整体工程目录结构:
这里写图片描述

这里要特别强调一点,有人可能不知道去哪里找android-support-v7-recyclerview.jar这个文件,其实它就在你下载的sdk目录下,我的是在D:\Program Files\Android\android-sdk\extras\android\support\v7\recyclerview\libs,直接把这个文件拷贝到自己工程libs目录下即可。不建议在网上找这个jar包,可能会由于版本问题不能使用。

要使用RecyclerView,和ListView一样,先在布局文件中引用:


activity_main.xml

<LinearLayout 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:background="#000000" android:orientation="vertical" tools:context="com.example.recyclerview_waterfall.MainActivity" > <LinearLayout
 android:layout_width="match_parent" android:layout_height="48dp" android:gravity="right"> <ImageView
 android:id="@+id/add" android:layout_width="24dp" android:layout_margin="12dp" android:layout_height="24dp" android:src="@drawable/add" /> </LinearLayout> <android.support.v7.widget.RecyclerView
 android:id="@+id/lv" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>
  
 
  • 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

上面是主布局文件,再看看Item的布局文件:


<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:padding="1dp" android:layout_height="wrap_content" > <ImageView
 android:id="@+id/iv" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#B0E0E6" android:src="@drawable/ic_launcher" /> <TextView
 android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@null" android:textSize="18sp" />

</FrameLayout>
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

item布局文件中就两样东西,一个TextView,一张图片。使用FrameLayout让两个空间重叠在一起。
好了,布局说完了就该说MainActivity了,毫无疑问,先要初始化RecyclerView:

rv = (RecyclerView) findViewById(R.id.lv); rv.setHasFixedSize(true); StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager( 3, StaggeredGridLayoutManager.VERTICAL); rv.setLayoutManager(layoutManager);
  
 
  • 1
  • 2
  • 3
  • 4
  • 5

使用StaggeredGridLayoutManager来实现瀑布流效果,它的构造方法中有两个参数,第一个是每行显示几个item,第二个参数是滚动的方向。
RecyclerView初始化完成之后我们就该初始化模拟数据了:

/** * 初始化模拟数据 */ private void initData() { list = new ArrayList<String>(); ivs = new ArrayList<Integer>(); heights = new ArrayList<Integer>(); for (int i = 'A'; i <= 'Z'; i++) { list.add("" + (char) i); heights.add((int) (100 + Math.random() * 300)); } ivs.add(R.drawable.p1); ivs.add(R.drawable.p2); ivs.add(R.drawable.p3); ivs.add(R.drawable.p4); ivs.add(R.drawable.p5); ivs.add(R.drawable.p6); ivs.add(R.drawable.p7); ivs.add(R.drawable.p8); ivs.add(R.drawable.p9); ivs.add(R.drawable.p10); ivs.add(R.drawable.p11); ivs.add(R.drawable.p12); ivs.add(R.drawable.p13); ivs.add(R.drawable.p14); ivs.add(R.drawable.p15); ivs.add(R.drawable.p16); ivs.add(R.drawable.p17); ivs.add(R.drawable.p18); ivs.add(R.drawable.p19); ivs.add(R.drawable.p20); ivs.add(R.drawable.p21); ivs.add(R.drawable.p22); ivs.add(R.drawable.p23); ivs.add(R.drawable.p24); ivs.add(R.drawable.p25); ivs.add(R.drawable.p26); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); mScreenWidth = dm.widthPixels; }
  
 
  • 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

这里主要有四个数据要初始化:
list表示TextView上显示的数据
ivs表示ImageView上显示图片的id
heights表示每个item的高,因为瀑布流中item高度不一,所以我们通过随机数来设定不同的高度。
最后一个mScreenWidth表示屏幕的宽度,我们要根据每行显示几个item来动态设定每个item的宽度。

做完这些就可以new一个Adapter了:

public class WaterFallAdapter extends Adapter { private Context context; private List<String> list; private LayoutInflater layoutInflater; private List<Integer> heights; private List<Integer> ivs; private int mScreenWidth; public OnItemClickListener listener; public interface OnItemClickListener { void onItemClick(View v, int position); void onItemLongClick(View v, int position); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.listener = onItemClickListener; } public WaterFallAdapter(Context context, List<String> list, List<Integer> heights, List<Integer> ivs, int mScreenWidth) { this.context = context; this.list = list; this.heights = heights; this.ivs = ivs; this.mScreenWidth = mScreenWidth; layoutInflater = LayoutInflater.from(context); } @Override public int getItemCount() { return ivs.size(); } @Override public void onBindViewHolder(ViewHolder viewHolder, final int position) { final MyViewHolder vHolder = (MyViewHolder) viewHolder; LayoutParams tvLp = vHolder.tv.getLayoutParams(); tvLp.height = heights.get(position); tvLp.width = mScreenWidth / 3; vHolder.tv.setLayoutParams(tvLp); vHolder.tv.setText(list.get(position)); vHolder.iv.setLayoutParams(tvLp); vHolder.iv.setImageResource(ivs.get(position)); vHolder.iv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int position2 = vHolder.getPosition(); listener.onItemClick(v, position2); } }); vHolder.iv.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { int position2 = vHolder.getPosition(); listener.onItemLongClick(v, position2); return true; } }); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int pos) { View v = layoutInflater.inflate(R.layout.item, null); ViewHolder vh = new MyViewHolder(v); return vh; } public static class MyViewHolder extends RecyclerView.ViewHolder { public TextView tv; public ImageView iv; public MyViewHolder(View itemView) { super(itemView); tv = (TextView) itemView.findViewById(R.id.tv); iv = (ImageView) itemView.findViewById(R.id.iv); } }
}
  
 
  • 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

RecyclerView中我们使用ViewHolder时要继承RecyclerView.ViewHolder,在这里初始化item,至于回收防止多次实例化等等都由RecyclerView来完成。onBindViewHolder是我们赋值的方法,在这里我们把数据匹配给item去显示。这里我们根据屏幕的宽度动态设置每个item的宽度。

RecyclerView最大的一个缺陷是没有提供点击事件,所以如果有需要的话要我们自己定义一个接口来完成这个动作。代码如上,我们在很多自定义View中都可以看到类似的方式。
定义好事件点击接口后,我们就可以在MainActivity中调用了:

 myAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemLongClick(View v, int position) { Toast.makeText(MainActivity.this, position + "--long click", Toast.LENGTH_SHORT).show(); list.remove(position); ivs.remove(position); myAdapter.notifyItemRemoved(position); } @Override public void onItemClick(View v, int position) { Toast.makeText(MainActivity.this, position + "--click", Toast.LENGTH_SHORT).show(); } });
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

点击直接弹出一个Toast,长按删除该项,删除的时候系统有自带动画,当然我们也可以自定义删除动画。删除之后我们使用myAdapter.notifyItemRemoved(position);而不是使用notifyDataSetChanged()因为前者是局部刷新,只会刷新item变化的部分,而后者会整体刷新,这样会影响动画效果的显示。

最后再来看看右上角点击事件:

add = (ImageView) findViewById(R.id.add); add.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { list.add(1, "大家好,我是新来的,请多多关照"); ivs.add(1, ivs.get((int) (Math.random() * 26))); myAdapter.notifyItemInserted(1); } });
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意刷新方式是一样的。数据添加的位置也是数据显示的位置。

好了,就简单介绍这么多,有问题欢迎留言讨论。

本工程源码下载

文章来源: wangsong.blog.csdn.net,作者:_江南一点雨,版权归原作者所有,如需转载,请联系作者。

原文链接:wangsong.blog.csdn.net/article/details/48086185

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。