Android手把手教你实现卡片式瀑布流效果

卡片式的瀑布流效果是一种非常美观的UI设计,自从Android 5.0的 RecyclerView出现以后,实现瀑布流变得十分简单,本文将一步步带领读者去实现一个卡片式的瀑布流布局。

一、先上效果图

源码上传在git上上,下载直接用Android Studio打开即可https://github.com/WangLaoSeng/waterfall

二、代码实现卡片式瀑布流

1. 涉及到要使用的类和控件

类或控件 介绍 作用
RecyclerView 5.0出现的类似于ListView的控件 用它的布局管理器实现两列“ListView”效果
StaggeredGridLayoutManager 交错布局管理器 实现两列“ListView”效果
RecyclerView.Adapter 数据适配器 与ListView的Adapter类似,写法上不同。
CardView 同样是5.0新出的控件 实现圆角效果,省去了自己写Drawble,这个可要可不要。
Fresco 图片开源框架 为了简化从网上下载图片的过程就使用了它做快速演示,如想了解Fresco的详情,请看本人另一篇博客:Fresco图片框架简介及使用(可做圆角图片)

2. 在Gradle中添加RecyclerView、Fresco和CardView需要的依赖

compile 'com.android.support:recyclerview-v7:24.2.0'compile 'com.facebook.fresco:fresco:0.14.1'compile 'com.android.support:cardview-v7:25.0.0'

3. 在Activity的布局文件中使用RecyclerView

<?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_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#F0F0F0"    tools:context="com.testwaterfall.MainActivity"    >    <android.support.v7.widget.RecyclerView        android:id="@+id/recyclerview"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:scrollbars="none"        >android.support.v7.widget.RecyclerView>RelativeLayout>

4. 构建RecyclerView的子Item View,命名为recyclerview_item.xml,这个布局里面主要是一张明显的图片和明星的名字。(这里的嵌套层数有点多,不是个好案例,为了省事就这样写了。)

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:fresco="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_margin="10dp"    android:background="#F0F0F0"    android:orientation="vertical"    android:padding="5dp"    >    <android.support.v7.widget.CardView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="#FFFFFF"        app:cardCornerRadius="5dp"        >        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:paddingBottom="5dp"            android:paddingLeft="6dp"            android:paddingRight="6dp"            android:paddingTop="10dp"            android:orientation="vertical"            >            <com.facebook.drawee.view.SimpleDraweeView                android:id="@+id/user_avatar"                android:layout_width="match_parent"                android:layout_height="wrap_content"                fresco:actualImageScaleType="centerCrop"                />            <TextView                android:id="@+id/user_name"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:layout_gravity="center"                android:gravity="center"                />        LinearLayout>    android.support.v7.widget.CardView>LinearLayout>

5. 编写RecyclerView的数据适配器WaterFallAdapter

public class WaterFallAdapter extends RecyclerView.Adapter {    private Context mContext;    private List mData; //定义数据源    //定义构造方法,默认传入上下文和数据源    public WaterFallAdapter(Context context, List data) {        mContext = context;        mData = data;    }    @Override  //将ItemView渲染进来,创建ViewHolder    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = LayoutInflater.from(mContext).inflate(R.layout.recyclerview_item, null);        return new MyViewHolder(view);    }    @Override  //将数据源的数据绑定到相应控件上    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        MyViewHolder holder2 = (MyViewHolder) holder;        PersonCard personCard = mData.get(position);        Uri uri = Uri.parse(personCard.avatarUrl);        holder2.userAvatar.setImageURI(uri);        holder2.userAvatar.getLayoutParams().height = personCard.imgHeight; //从数据源中获取图片高度,动态设置到控件上        holder2.userName.setText(personCard.name);    }    @Override    public int getItemCount() {        if (mData != null) {            return mData.size();        }        return 0;    }    //定义自己的ViewHolder,将View的控件引用在成员变量上    public class MyViewHolder extends RecyclerView.ViewHolder {        public SimpleDraweeView userAvatar;        public TextView userName;        public MyViewHolder(View itemView) {            super(itemView);            userAvatar = (SimpleDraweeView) itemView.findViewById(R.id.user_avatar);            userName = (TextView) itemView.findViewById(R.id.user_name);        }    }}

6. 构建一个数据Model,明星,以便于传递数据。

public class PersonCard implements Serializable{    public String avatarUrl; //明显头像的Url    public String name;  //明显的名字    public int imgHeight;  //头像图片的高度}

7. 在Activity里面初始化界面和生成、绑定数据

public class MainActivity extends Activity {    private RecyclerView mRecyclerView;    private RecyclerView.LayoutManager mLayoutManager;    private WaterFallAdapter mAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        init();    }    private void init() {        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);        //设置布局管理器为2列,纵向        mLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);        mAdapter = new WaterFallAdapter(this, buildData());        mRecyclerView.setLayoutManager(mLayoutManager);        mRecyclerView.setAdapter(mAdapter);    }    //生成6个明星数据,这些Url地址都来源于网络    private List buildData() {        String[] names = {"邓紫棋","范冰冰","杨幂","Angelababy","唐嫣","柳岩"};        String[] imgUrs = {"https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1477122728&di=21924aeef8f7847a651fc8bf00a28f49&src=http://www.tengtv.com/file/upload/201609/18/232836341.jpg",                "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1477122795&di=f740bd484870f9bcb0cafe454a6465a2&src=http://tpic.home.news.cn/xhCloudNewsPic/xhpic1501/M08/28/06/wKhTlVfs1h2EBoQfAAAAAF479OI749.jpg",                "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=673651839,1464649612&fm=111&gp=0.jpg",                "https://ss0.baidu.com/94o3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=fd90a83e900a304e4d22a7fae1c9a7c3/d01373f082025aafa480a2f1fcedab64034f1a5d.jpg",                "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1849074283,1272897972&fm=111&gp=0.jpg",                "https://ss0.baidu.com/-Po3dSag_xI4khGko9WTAnF6hhy/image/h%3D200/sign=005560fc8b5494ee982208191df4e0e1/c2fdfc039245d68827b453e7a3c27d1ed21b243b.jpg",        };        List list = new ArrayList<>();        for(int i=0;i<6;i++) {            PersonCard p = new PersonCard();            p.avatarUrl = imgUrs[i];            p.name = names[i];            p.imgHeight = (i % 2)*100 + 400; //偶数和奇数的图片设置不同的高度,以到达错开的目的            list.add(p);        }        return list;    }}

三、总结

瀑布流实现的关键有3点:

  • 使用RecyclerView和它的StaggeredGridLayoutManager布局管理器,

  • 其次在于列表中的Item View的高度并不一样,这样才能达到交错开来的效果

  • 子Item的布局,让两列之间,上下之间能有一定的“空隙”,这才能达成视觉上的效果。

更多相关文章

  1. 【基础系列】Input控件专题
  2. Android学习笔记:常用控件 RadioGroup和CheckBox
  3. Android表格布局之设置边框
  4. Android优化之布局优化
  5. Android(安卓)Fragment用法详解(2)--动态添加Fragment
  6. Android应用屏幕适应问题的解决
  7. android列表【android开发记录片】android下实现圆角列表布局控
  8. [Android(安卓)实例] 史上最全的Android的Tab与TabHost讲解
  9. Android设置 Wedgit透明度

随机推荐

  1. Linux入门基础知识(1)-------Linux基础概念
  2. Android(安卓)Hook 机制之实战模拟
  3. Android Studio升级后报 method not foun
  4. 开始写笔记
  5. Android(安卓)UI开源组件库BottomView ,第
  6. android NDK mk文件模板
  7. Android开发指南中文版(七)Content Provide
  8. Android View底层到底是怎么绘制的
  9. Android测试入门篇
  10. Android开发者e周报 第2期