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

最近有时间研究了一下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>


上面是主布局文件,再看看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>


item布局文件中就两样东西,一个TextView,一张图片。使用FrameLayout让两个空间重叠在一起。

好了,布局说完了就该说MainActivity了,毫无疑问,先要初始化RecyclerView:

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

使用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;
    }

这里主要有四个数据要初始化:

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);
        }

    }
}

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();
            }
        });

点击直接弹出一个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);
            }
        });

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

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

本工程源码下载

版权声明:本文为博主原创文章,未经博主允许不得转载。若有错误地方,还望批评指正,不胜感激。

时间: 2024-10-16 15:06:17

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

Java开源生鲜电商平台-Java后端生成Token架构与设计详解(源码可下载)

Java开源生鲜电商平台-Java后端生成Token架构与设计详解(源码可下载) 目的:Java开源生鲜电商平台-Java后端生成Token目的是为了用于校验客户端,防止重复提交. 技术选型:用开源的JWT架构. 1.概述:在web项目中,服务端和前端经常需要交互数据,有的时候由于网络相应慢,客户端在提交某些敏感数据(比如按照正常的业务逻辑,此份数据只能保存一份)时,如果前端多次点击提交按钮会导致提交多份数据,这种情况我们是要防止发生的. 2.解决方法: ①前端处理:在提交之后通过js立即将按钮

RecyclerView实现瀑布流效果(二)

在上篇中我们知道RecyclerView中默认给我们提供了三种布局管理器,分别是LinearLayoutManager.GridLayoutManager.StaggeredGridLayoutManager.其中StaggeredGridLayoutManager可实现交错式网格布局,正好可以用来实现瀑布流. 下面先看看效果图吧,再贴代码: 其中大部分内容实现其实是和上篇文章是一样的,就不多叙述了,就一个地方不同,就是我们在适配器中绑定ViewHolder的方法中需要重新给我们的itemVie

转载—— android 瀑布流的实现详解,附源码

介绍 参考自:https://github.com/dodola/android_waterfall,因为原来的代码封装不好,所以,我根据源码的思路,重新写了一遍,所以有了现在这个项目:https://github.com/youxilua/waterfall4android 原作者表示: 试过在1万张可以流畅的滑动,不出现内存溢出情况 设计思路 之前的作者的自定义view 只有主滑动一层,其他的设置要在相应的活动设置,个人觉得,重用起来比较麻烦,所以决定封装一层.现在定义一个默认的瀑布流只需5

Shiro的Filter机制详解---源码分析

Shiro的Filter机制详解 首先从spring-shiro.xml的filter配置说起,先回答两个问题: 1, 为什么相同url规则,后面定义的会覆盖前面定义的(执行的时候只执行最后一个). 2, 为什么两个url规则都可以匹配同一个url,只执行第一个呢. 下面分别从这两个问题入手,最终阅读源码得到解答. 问题一解答 相同url但定义在不同的行,后面覆盖前面 如 /usr/login.do=test3 /usr/login.do=test1,test2 不会执行test3的filter

美容预约系统开发详解源码模式设计

美容预约系统开发(李想.185.6504.8478)美容一词可以从两个角度来理解.首选是"容"这个字,其次是"美"."容"包括脸.仪态.和修饰三层意思."美"则具有形容词和动词的两层含义.形容词表明的是美容的结果和目的是美丽的好看的:动词则表明的是美容的过程,即美化和改变的意思.预约系统是一种通过微信公众号或者app平台来实现一键预约服务的系统,常见的有游泳馆一键预约,美容一键预约,健身一键预约,按摩一键预约,诊所一键预约,试

凌煜云商城系统开发详解源码设计

凌煜云商城系统开发(李想.185.6504.8478)互联网是全球性的.这就意味着这个网络不管是谁发明了它,是属于全人类的.互联网的结构是按照"包交换"的方式连接的分布式网络.因此,在技术的层面上,互联网绝对不存在中央控制的问题.也就是说,不可能存在某一个国家或者某一个利益集团通过某种技术手段来控制互联网的问题.反过来,也无法把互联网封闭在一个国家之内-除非建立的不是互联网.然而,与此同时,这样一个全球性的网络,必须要有某种方式来确定联入其中的每一台主机.在互联网上绝对不能出现类似两个

Python-Flask框架之——图书管理系统 , 附详解源码和效果图 !

该图书管理系统要实现的功能: 1. 可以通过添加窗口添加书籍或作者, 如果要添加的作者和书籍已存在于书架上, 则给出相应的提示. 2. 如果要添加的作者存在, 而要添加的书籍书架上没有, 则将该书籍添加到该作者栏. 3. 如果要添加的作者和书籍都不存在于书架上 , 则将书籍和作者一起添加. 4. 每个书籍和作者旁边都有一个删除按钮 , 点击删除书籍的按钮可以将该书籍删除 , 若某作者栏的书籍全部删除完毕则显示"无". 5. 若直接点击删除作者按钮, 则可以将该作者和其书籍一起全部删掉.

Python安装、配置图文详解(转载)

Python安装.配置图文详解 目录: 一. Python简介 二. 安装python 1. 在windows下安装 2. 在Linux下安装 三. 在windows下配置python集成开发环境(IDE) 1. 在Eclipse中安装PyDev插件 2. 配置Python Interpreters 四. 创建Python Project 五. 编写HelloWorld 六. 小结 一. Python简介: Python在Linux.windows.Mac os等操作系统下都有相应的版本,不管在

wpf 客户端【JDAgent桌面助手】开发详解(三) 瀑布流效果实现与UI虚拟化优化大数据显示

目录区域: 业余开发的wpf 客户端终于完工了..晒晒截图 wpf 客户端[JDAgent桌面助手]开发详解-开篇 wpf 客户端[JDAgent桌面助手]详解(一)主窗口 圆形菜单... wpf 客户端[JDAgent桌面助手]开发详解(二)桌面宠物制作详解 因为前段时候有很多的事情 比较忙,自从上次写完博客之后很久没有更新了. 用WPF制作的京东桌面助手.这个作品是参加比赛的,自己花费了很多心思和时间在里面,最终的作品效果和比赛的结果还是令人满意的. 作品感觉不说很fashion,也足够细致