Android手把手教你实现卡片式瀑布流效果(RecyclerView+CardView,附源码)
16lz
2021-01-24
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的布局,让两列之间,上下之间能有一定的“空隙”,这才能达成视觉上的效果。
更多相关文章
- 【基础系列】Input控件专题
- Android学习笔记:常用控件 RadioGroup和CheckBox
- Android表格布局之设置边框
- Android优化之布局优化
- Android(安卓)Fragment用法详解(2)--动态添加Fragment
- Android应用屏幕适应问题的解决
- android列表【android开发记录片】android下实现圆角列表布局控
- [Android(安卓)实例] 史上最全的Android的Tab与TabHost讲解
- Android设置 Wedgit透明度