RecyclerView实现瀑布流布局
RecyclerView实现瀑布流布局
注意:内容来源于郭神《第二行代码》。郭神博客http://blog.csdn.net/guolin_blog
一、RecyclerView是干什么的?
简单点我们可以先把它理解为ListView的一个升级版,因为它不仅可以轻松的完成ListView的各种功能,而且还优化了ListView中存在的各种不足之处。
二、RecyclerView的基本用法
因为Android团队将RecyclerView定义在了support库当中,因此要使用这个控件,我们首先要在项目的build.gradle中添加相应的依赖库才行。
打开app/build.gradle文件,在dependencies闭包下添加如下内容
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:recyclerview-v7:24.2.1'
}
添加完之后要记得点击一下右上方的Sync Now来进行同步。然后就可以在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" tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
这里要注意:因为RecyclerView不是内置在系统的SDK中,所以引用的时候要把完整的包路径写出来
这里我们先用RecyclerView来实现和ListView相同的效果如图所示:
因此这里我们和ListView一样要先准备用来展示的数据: (我们准备在每一个Item上展示一个水果的图片和它的名字即一个ImageView和TextView)
首先先定义一个水果的实体类Fruit,代码如下:
public class Fruit {
private int imageId;
private String name;
public Fruit(int imageId, String name) {
this.imageId = imageId;
this.name = name;
}
public int getImageId() {
return imageId;
}
public String getName() {
return name;
}
}
Fruit类中只有两个字段,name表示水果的名字,imageId表示水果对应图片的资源id。
然后像ListView一样需要为我们的子项指定一个我们自定义的布局,在layout目录下新建fruit-item.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_gravity="center_vertical"
/>
</LinearLayout>
这些都准备好了,接下来就需要为 RecyclerView 准备一个适配器了,新建FruitAdapter类,让这个适配器继承自 RecyclerView.Adapter ,并将泛型指定为 FruitAdapter.ViewHolder 。 其中 ViewHolder 是我们在 FruitAdapter 中定义的一个内部类,代码如下所示:
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> fruits;
/**
* 定义内部类 Viewholder 继承 RecyclerView.ViewHolder
* 这个构造传入的参数 view 就是RecyclerView子项的最外层布局,所以我们就可以通过findViewById()方法来获取布局中的ImageView和TextView的实例了
*/
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView fruitImage;
TextView fruitName;
public ViewHolder(View view) {
super(view);
fruitImage= (ImageView) view.findViewById(R.id.fruit_image);
fruitName= (TextView) view.findViewById(R.id.fruit_name);
}
}
/**
* 定义一个构造函数 用来把展示的数据传过来 并赋值给一个全局变量fruits
* @param fruits
*/
public FruitAdapter(List<Fruit> fruits){
this.fruits=fruits;
}
// 下面这三个方法都是重写的
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
// 将fruit_item布局加载进来
View view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.fruit_item,viewGroup,false);
//创建ViewHolder实例
ViewHolder holder=new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int i) {
//对RecyclerView 的每个子项进行赋值
Fruit fruit=fruits.get(i);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
//告诉RecyclerView 一共有多少个子项 返回数据源的长度
return fruits.size();
}
}
适配器准备好了,下面就可以开始使用RecyclerView了,修改mainActivity.calss中的代码,如下所示:
public class MainActivity extends Activity {
private List<Fruit> fruits=new ArrayList<Fruit>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(); //初始化水果数据
RecyclerView recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager=new LinearLayoutManager(this); //创建LinearLayoutManager 用来指定RecyclerView的布局方式
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter=new FruitAdapter(fruits);
recyclerView.setAdapter(adapter);
}
private void init() {
for (int i = 0; i < 2; i++) {
Fruit apple = new Fruit(R.drawable.apple_pic,"apple");
fruits.add(apple);
Fruit banana = new Fruit(R.drawable.banana_pic,"banana");
fruits.add(banana);
Fruit orange = new Fruit(R.drawable.orange_pic,"orange");
fruits.add(orange);
Fruit watermelon = new Fruit(R.drawable.watermelon_pic, "watermelon");
fruits.add(watermelon);
Fruit pear = new Fruit(R.drawable.pear_pic,"pear");
fruits.add(pear);
Fruit grape = new Fruit(R.drawable.grape_pic,"grape");
fruits.add(grape);
Fruit pineapple = new Fruit(R.drawable.pineapple_pic,"pineapple");
fruits.add(pineapple);
Fruit strawberry = new Fruit(R.drawable.strawberry_pic,"strawberry");
fruits.add(strawberry);
Fruit cherry = new Fruit(R.drawable.cherry_pic,"cherry");
fruits.add(cherry);
Fruit mango = new Fruit(R.drawable.mango_pic,"mango");
fruits.add(mango);
}
}
}
到这里我们就完成了RecyclerView 和ListView 一样的功能了 先运行程序,效果图如下:
到这里你可能觉得RecyclerView 并没有ListView 方便好用,别急,下面你会看到RecyclerView更强大的功能。
三、实现横向滚动布局
如果你还认为ListView比RecyclerView好用,那么ListView能够实现 横向滚动布局么? 与ListView相比,RecyclerView实现横向滚动非常简单,只需要改动几行代码就可以了
为了节省时间下面我们将在原来的代码上进行改动,首先要对展示每个Item布局的fruit_item.xml 进行修改,因为里面的元素是水平排列的 适合纵向滚动,而如果我们要实现横向滚动的话,应该把水平排列改为垂直排列才比较合理。如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="100dp" android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal"
/>
</LinearLayout>
可以看到我们将Linearlayout的布局改为垂直方向排列,并把宽度设为100dp,这里是因为每个图片的文字长度是不一样的,为了美观把wrap_content 改为了100dp。
接下来修改MainActivity中的代码,如下所示:
public class MainActivity extends Activity {
private List<Fruit> fruits=new ArrayList<Fruit>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(); //初始化水果数据
RecyclerView recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager=new LinearLayoutManager(this); //创建LinearLayoutManager 用来指定RecyclerView的布局方式
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); //在这里设置为横向滚动,因为纵向滚动为默认,所以刚才并没有设置
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter=new FruitAdapter(fruits);
recyclerView.setAdapter(adapter);
}
......
}
这样我们的横向滚动就完成了,看一下效果图:
到这里RecyclerView的强大还没有展示出来呢,接下来我们来看一个更强大 的 瀑布流布局:
四、瀑布流布局
首先我们还是先来修改一下fruit_item的代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_margin="5dp" android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_gravity="left"
/>
</LinearLayout>
接着修改MainActivity的代码:
public class MainActivity extends Activity {
private List<Fruit> fruits=new ArrayList<Fruit>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(); //初始化水果数据
RecyclerView recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
//这里就不能使用Linearlayout了,要使用RecyclerView 给我们提供的StaggeredGridLayoutManager
StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter=new FruitAdapter(fruits);
recyclerView.setAdapter(adapter);
}
//这里因为Fruit名字都是固定的体现不出瀑布流的特点,所以将fruit名字变为随机的长度
private void init(){
for (int i = 0; i < 2; i++) {
Fruit apple = new Fruit(R.drawable.apple_pic, getRandomLengthName("apple"));
fruits.add(apple);
Fruit banana = new Fruit(R.drawable.banana_pic, getRandomLengthName("banana"));
fruits.add(banana);
Fruit orange = new Fruit(R.drawable.orange_pic, getRandomLengthName("orange"));
fruits.add(orange);
Fruit watermelon = new Fruit(R.drawable.watermelon_pic, getRandomLengthName("watermelon"));
fruits.add(watermelon);
Fruit pear = new Fruit(R.drawable.pear_pic, getRandomLengthName("pear"));
fruits.add(pear);
Fruit grape = new Fruit(R.drawable.grape_pic, getRandomLengthName("grape"));
fruits.add(grape);
Fruit pineapple = new Fruit(R.drawable.pineapple_pic, getRandomLengthName("pineapple"));
fruits.add(pineapple);
Fruit strawberry = new Fruit(R.drawable.strawberry_pic, getRandomLengthName("strawberry"));
fruits.add(strawberry);
Fruit cherry = new Fruit(R.drawable.cherry_pic, getRandomLengthName("cherry"));
fruits.add(cherry);
Fruit mango = new Fruit(R.drawable.mango_pic, getRandomLengthName("mango"));
fruits.add(mango);
}
}
private String getRandomLengthName(String name){
Random random=new Random();
int length=random.nextInt(20)+1;
StringBuilder builder=new StringBuilder();
for (int i=0;i<length;i++){
builder.append(name);
}
return builder.toString();
}
}
这样几步修改就实现了瀑布流布局,好了让我们来看看效果:
上一篇: Python socket 编程