RecyclerView學(xué)習(xí)筆記
一钝域、RecyclerView的定義
在以前的開(kāi)發(fā)中,我們經(jīng)常使用ListView來(lái)實(shí)現(xiàn)列表的功能∨呶現(xiàn)在Google為我們提供了一個(gè)更強(qiáng)大的滾動(dòng)控件RecyclerView拘领,他不僅可以實(shí)現(xiàn)ListView的功能褐墅,還優(yōu)化了ListView的效率問(wèn)題痴颊。RecyclerView還支持橫向滾動(dòng)和瀑布流赏迟,所以現(xiàn)在Google官方更加推薦使用RecyclerView進(jìn)行開(kāi)發(fā)。
二蠢棱、RecyclerView的用法
-
打開(kāi)Android Studio的project structrue設(shè)置锌杀,在dependencies的閉包中導(dǎo)入RecyclerView的依賴庫(kù)。
image.png 在布局文件中添加以下代碼加入RecyclerView控件
<?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="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
- 創(chuàng)建數(shù)據(jù)源Sport
public class Sport {
private String name;
private int imageId;
public Sport(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
// 獲取項(xiàng)目名稱
public String getName() {
return name;
}
// 獲取項(xiàng)目圖片ID
public int getImageId() {
return imageId;
}
}
- 為RecyclerView準(zhǔn)備一個(gè)適配器泻仙,新建SportAdapter類糕再,繼承自RecyclerView.adapter,適配器的泛型指定為內(nèi)部類SportAdapter.ViewHolder玉转。
public class SportAdapter extends RecyclerView.Adapter<SportAdapter.ViewHolder> {
private List<Sport> sportList;
// 靜態(tài)內(nèi)部類ViewHolder保存控件
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView sportImage;
TextView sportName;
// item為RecyclerView子項(xiàng)的外層布局
public ViewHolder(View itemView) {
super(itemView);
sportImage = itemView.findViewById(R.id.sport_image);
sportName = itemView.findViewById(R.id.sport_name);
}
}
// 傳入數(shù)據(jù)源sportList賦值給全局變量
public SportAdapter(List<Sport> sportList) {
this.sportList = sportList;
}
// 創(chuàng)建ViewHolder實(shí)例,先加載布局亿鲜,再把布局傳入viweHolder的實(shí)例中
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.sport_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
// 通過(guò)position獲取當(dāng)前實(shí)例,對(duì)于RecyclerView子項(xiàng)的數(shù)據(jù)進(jìn)行賦值
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Sport sport = sportList.get(position);
holder.sportImage.setImageResource(sport.getImageId());
holder.sportName.setText(sport.getName());
}
// RecyclerView的子項(xiàng)個(gè)數(shù)
@Override
public int getItemCount() {
return sportList.size();
}
}
- 修改MainActivity的代碼
public class MainActivity extends AppCompatActivity {
private List<Sport> sportList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化數(shù)據(jù)
initSport();
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// 為RecyclerView指定線性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// 設(shè)置適配器
SportAdapter adapter = new SportAdapter(sportList);
recyclerView.setAdapter(adapter);
}
private void initSport() {
for (int i = 0; i < 2; i++) {
Sport archer = new Sport("archer", R.drawable.archer);
sportList.add(archer);
Sport athlete = new Sport("athlete", R.drawable.athlete);
sportList.add(athlete);
Sport badminton = new Sport("badminton", R.drawable.badminton);
sportList.add(badminton);
Sport bicycle = new Sport("bicycle", R.drawable.bicycle);
sportList.add(bicycle);
Sport diving = new Sport("diving", R.drawable.diving);
sportList.add(diving);
Sport fisher = new Sport("fisher", R.drawable.fisher);
sportList.add(fisher);
Sport pingpong = new Sport("pingpong", R.drawable.pingpong);
sportList.add(pingpong);
Sport swimming = new Sport("swimming", R.drawable.swimming);
sportList.add(swimming);
Sport volleyball = new Sport("volleyball", R.drawable.volleyball);
sportList.add(volleyball);
}
}
}
這樣就實(shí)現(xiàn)了RecyclerView的縱向滾動(dòng)功能冤吨,效果圖如下:
三、實(shí)現(xiàn)橫向滾動(dòng)和瀑布流
實(shí)現(xiàn)橫向滾動(dòng)的效果
- 修改sport_item布局文件代碼,讓圖片和文字縱向排列,指定寬度讓每個(gè)item一樣大饶套。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:showDividers="middle">
<ImageView
android:id="@+id/sport_image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/sport_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp" />
</LinearLayout>
- 修改MainActivity漩蟆,在layoutManager中傳入LinearLayoutManager.HORIZONTAL
public class MainActivity extends AppCompatActivity {
private List<Sport> sportList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
... ...
// 為RecyclerView指定線性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
... ...
}
... ...
}
}
這樣就實(shí)現(xiàn)了RecyclerView的橫向滾動(dòng)功能,效果圖如下:
RecyclerView因?yàn)樘峁┝薒ayoutManager,LayoutManager制定了一套可拓展的布局接口妓蛮,子類(例如LinearLayoutManager)只要按照接口來(lái)實(shí)現(xiàn)就可以呈現(xiàn)不同的效果怠李。
??除了LinearLayoutManager之外,RecyclerView還提供了GirdLayouManager實(shí)現(xiàn)網(wǎng)格布局和StaggeredGridLayoutManager實(shí)現(xiàn)瀑布流布局。
實(shí)現(xiàn)瀑布流的效果
- 修改sport_item的代碼,讓瀑布流的寬度根據(jù)布局列數(shù)自動(dòng)適配捺癞,讓文字居左顯示夷蚊。
<?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_height="wrap_content"
android:layout_margin="5dp">
<ImageView
android:id="@+id/sport_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/sport_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp" />
</LinearLayout>
- 修改MainActivity,指定RecyclerView的布局為StaggeredGrildLayout髓介,布局分為4列惕鼓。設(shè)置getRandomLengthName()來(lái)使每個(gè)item的文字段不一樣長(zhǎng),方便看出瀑布流效果唐础。
public class MainActivity extends AppCompatActivity {
private List<Sport> sportList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化數(shù)據(jù)
initSport();
RecyclerView recyclerView = findViewById(R.id.recycler_view);
// 為RecyclerView指定線性布局
// LinearLayoutManager layoutManager = new LinearLayoutManager(this);
// layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
// 為RecyclerView指定4列的瀑布流布局
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(
4, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
// 設(shè)置適配器
SportAdapter adapter = new SportAdapter(sportList);
recyclerView.setAdapter(adapter);
}
// 寫(xiě)死的本地?cái)?shù)據(jù)
private void initSport() {
for (int i = 0; i < 3; i++) {
Sport archer = new Sport(getRamdomLengthName("archer"), R.drawable.archer);
sportList.add(archer);
... ...
Sport volleyball = new Sport(getRamdomLengthName("volleyball"), R.drawable.volleyball);
sportList.add(volleyball);
}
}
// 把名稱copy隨機(jī)次形成一段文字箱歧,使每個(gè)item不一樣長(zhǎng)
private String getRamdomLengthName(String sportName) {
Random random = new Random();
int length = random.nextInt(15) + 1;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++) {
builder.append(sportName);
}
return builder.toString();
}
}
這樣就實(shí)現(xiàn)了RecyclerView的瀑布流布局,效果圖如下:
四一膨、RecyclerView的點(diǎn)擊事件
一般來(lái)說(shuō)呀邢,無(wú)論是ListView還是RecyclerView每個(gè)item都應(yīng)該有點(diǎn)擊事件,例如我們的新聞列表豹绪,點(diǎn)擊進(jìn)去應(yīng)該都有新聞內(nèi)容价淌。RecyclerView沒(méi)有像ListView一樣的API去setOnItemClickListener(),點(diǎn)擊事件由View去注冊(cè)瞒津,但也更加靈活了蝉衣。
- 修改apapter的代碼,在ViewHolder中添加view變量來(lái)保存item布局實(shí)例仲智,然后在onCreateViewHolder()中為item和image分別注冊(cè)不同的點(diǎn)擊事件买乃,由于image是item布局的子View,所以當(dāng)我們點(diǎn)擊事件的時(shí)候钓辆,image會(huì)攔截并處理點(diǎn)擊事件剪验,事件消耗完之后父View item的點(diǎn)擊事件就不會(huì)響應(yīng)。
public class SportAdapter extends RecyclerView.Adapter<SportAdapter.ViewHolder> {
private List<Sport> sportList;
// 靜態(tài)內(nèi)部類ViewHolder保存控件
static class ViewHolder extends RecyclerView.ViewHolder {
View sportView;
public ImageView getSportImage() {
return sportImage;
}
ImageView sportImage;
TextView sportName;
// item為RecyclerView子項(xiàng)的外層布局
public ViewHolder(View itemView) {
super(itemView);
sportView = itemView;
sportImage = itemView.findViewById(R.id.sport_image);
sportName = itemView.findViewById(R.id.sport_name);
}
}
// 傳入數(shù)據(jù)源sportList賦值給全局變量
public SportAdapter(List<Sport> sportList) {
this.sportList = sportList;
}
// 創(chuàng)建ViewHolder實(shí)例,先加載布局前联,再把布局傳入viweHolder的實(shí)例中
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.sport_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
// 設(shè)置item項(xiàng)的點(diǎn)擊事件
holder.sportView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
Sport sport = sportList.get(position);
Toast.makeText(view.getContext(), "you click item " + sport.getName(),Toast.LENGTH_SHORT).show();
}
});
// 設(shè)置image的點(diǎn)擊事件
holder.sportImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
Sport sport = sportList.get(position);
Toast.makeText(view.getContext(), "you click image " + sport.getName(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}
... ...
}