Android中利用RecyclerView實現瀑布流效果
RecyclerView相比於傳統的ListView,功能更加強大,使用也比較方便,因此Android官方更加推薦使用RecycleView,未來也會有更多的程式逐漸從ListView轉向RecycleView。為此,首先先來了解下RecycleView的用法。當然,最先看的是效果圖:
RecycleView屬於新增的控制元件,為了讓RecyclerView在所有的Android版本上都能使用,系統將RecyclerView定義在support庫中,因此想要使用RecycleView這個控制元件,首先Android Studio要在專案的build.gradle中新增相應的依賴庫才行。eclipse的話,專案中要有V7包。
在專案的dependencies閉包中新增
compile 'com.android.support:recyclerview-v7:24.2.1'
新增完成後,在佈局檔案中新增控制元件時一定要寫全包名。如下所示:
<android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView>
和ListView一樣,複雜一點佈局都需要我們自己寫介面卡,為RecyclerView準備介面卡,讓其繼承自RecyclerView.Adapter,並將泛型指定為FruitAdapter.ViewHolder.其中ViewHolder是在FruitAdapter中定義的一個內部類,程式碼如下:
其中Fruit.java實體類程式碼如下:package com.example.administrator.myapplication; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import java.util.List; public class FruitAdapterRecyclerView extends RecyclerView.Adapter<FruitAdapterRecyclerView.ViewHolder> { private List<Fruit> mFruitList; static class ViewHolder extends RecyclerView.ViewHolder{ View fruitItemView; ImageView imageView; TextView textView; public ViewHolder(View itemView) { super(itemView); fruitItemView=itemView; imageView= (ImageView) itemView.findViewById(R.id.img); textView= (TextView) itemView.findViewById(R.id.tv); } } public FruitAdapterRecyclerView(List<Fruit> mFruitList) { this.mFruitList = mFruitList; } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item,viewGroup,false); final ViewHolder viewHolder=new ViewHolder(view); viewHolder.fruitItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position=viewHolder.getAdapterPosition(); Fruit fruit=mFruitList.get(position); Toast.makeText(v.getContext(),"點選的是itemview--"+fruit.getName(),Toast.LENGTH_SHORT).show(); } }); viewHolder.imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position=viewHolder.getAdapterPosition(); Fruit fruit=mFruitList.get(position); Toast.makeText(v.getContext(),"點選的是image--"+fruit.getName(),Toast.LENGTH_SHORT).show(); } }); return viewHolder; } @Override public void onBindViewHolder(ViewHolder viewHolder, int i) { Fruit fruit=mFruitList.get(i); viewHolder.imageView.setImageResource(fruit.getImgId()); viewHolder.textView.setText(fruit.getName()); } @Override public int getItemCount() { return mFruitList.size(); } }
package com.example.administrator.myapplication;
public class Fruit {
private String name;
private int imgId;
public Fruit(String name,int imgId) {
this.name = name;
this.imgId = imgId;
}
public String getName() {
return name;
}
public int getImgId() {
return imgId;
}
}
item的佈局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_margin="5dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_gravity="left" />
</LinearLayout>
剛開始的時候不容易理解,但是用的多了後,就發現比較好理解了,這裡和ListView中的介面卡類似首先定義了一個內部類ViewHolder,但是不同的是這裡的ViewHolder要繼承自RecyclerView.ViewHolder.然後在ViewHolder的建構函式中傳入View引數,這個引數通常是RecyclerView的子項ItemView的佈局,然後通過findViewById()方法來獲取佈局中的ImageView和TextView的例項。
和ListView中的介面卡一樣,RecyclerView的介面卡也有一個建構函式,通過這個方法將要展示的資料來源傳遞進去並賦值給全域性變數list,後續的操作都是基於此資料來源進行操作的。
由於FruitAdapter是繼承自RecyclerView.Adaper的,那麼就必須重寫onCreatViewHolder()、onBindViewHolder()和getItemCount()這3個方法,onCreatViewHolder()方法是用於建立ViewHolder例項的,我們在這個方法中將list_item的佈局載入進去。然後建立一個ViewHolder例項,並把加載出來的佈局傳入到建構函式中,最後將ViewHolder的例項返回;onBindViewHolder()方法是用於對RecyclerView子項的資料進行賦值的,會在每個子項被滾動到螢幕內的時候執行,這裡我們通過position引數,利用資料來源獲取子項的資料,然後將資料設定到子項的控制元件中;而getItemCount()方法就和ListView中的一樣了,它用於告訴RecyclerView一共有多少個子項。
相比於ListView,RecyclerView在Activity的實現方面有個小的不同,就是多了個LayoutManager。程式碼如下:
package com.example.administrator.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RecycleViewActivity extends Activity{
List<Fruit> list=new ArrayList<>();
RecyclerView recyclerView;
FruitAdapterRecyclerView fruitAdapterRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
initFruits();
recyclerView= (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
// linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
// recyclerView.setLayoutManager(linearLayoutManager);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
fruitAdapterRecyclerView=new FruitAdapterRecyclerView(list);
recyclerView.setAdapter(fruitAdapterRecyclerView);
}
private void initFruits() {
for (int i=0;i<3;i++){
Fruit fruit=new Fruit(setRandomLength("apple"),R.mipmap.apple_pic);
Fruit fruit2=new Fruit(setRandomLength("banana"),R.mipmap.banana_pic);
Fruit fruit3=new Fruit(setRandomLength("cherry"),R.mipmap.cherry_pic);
Fruit fruit4=new Fruit(setRandomLength("grape"),R.mipmap.grape_pic);
Fruit fruit5=new Fruit(setRandomLength("mango"),R.mipmap.mango_pic);
Fruit fruit6=new Fruit(setRandomLength("orange"),R.mipmap.orange_pic);
Fruit fruit7=new Fruit(setRandomLength("pear"),R.mipmap.pear_pic);
Fruit fruit8=new Fruit(setRandomLength("strawberry"),R.mipmap.strawberry_pic);
list.add(fruit);
list.add(fruit2);
list.add(fruit3);
list.add(fruit4);
list.add(fruit5);
list.add(fruit6);
list.add(fruit7);
list.add(fruit8);
}
}
public String setRandomLength(String str){
StringBuilder sb=new StringBuilder();
Random random=new Random();
int num=random.nextInt(19)+1;
for (int i = 0; i <num; i++) {
sb.append(str).append(" ");
}
return sb.toString();
}
}
這裡我們建立了一個LinearLayoutManager物件,並將它設定到RecyclerView當中,LayoutManager用於指定RecyclerView的佈局方式,這裡如果使用LinearLayoutManager是線性佈局的意思,可以實現和ListView中類似的效果。接下來就和ListView一樣了,建立FruitAdapter例項,然後將資料傳入到建構函式中,最後呼叫RecyclerView的setAdapter()方法來完成介面卡的設定。
當然,這裡我們要實現的是瀑布流效果,所以選用的是StaggeredGridLayoutManager來實現的,它接受兩個引數,第一個引數用於指定佈局的列數,第二個引數指定佈局的排列方向,最後還是將建立的例項設定到RecyclerView當中就行了。實現的效果如下:
RecyclerView的點選事件
和ListView一樣,控制元件要有點選事件才可以,不同於ListView的是,RecyclerView並沒有提供類似於setOnItemClickListener()方法,採用的是點選事件都是交給具體的View去註冊處理,相比於ListView中item中控制元件的點選事件的實現的話,要方便的多,這也就是RecyclerView的強大之處,可以輕鬆實現子項中任意控制元件或佈局的點選事件。
其中上面Adapter的第35行,註冊的是整體item的點選事件,而第43行設定的是item中控制元件的點選事件。
原始碼 點我下載