挑战练习8.8 RecyclerView ViewType
请在RecyclerView中创建两类列表项:一般性crime,以及需警方介入的crime。要完成这个挑战,你需要用到RecyclerView.Adapter的视图类别功能(view type)。在Crime对象里,再添加一个mRequiresPolice实例变量,使用它并借助getItemViewType(int)方法,确定该加载哪个视图到CrimeAdapter。
在onCreateViewHolder(ViewGroup,int)方法里,基于getItemViewType(int)方法返回的ViewType值,需要返回不同的ViewHolder。如果是一般性crime,就仍然使用原始布局;如果是需警方介入的crime,就使用一个带联系警方按钮的新布局。
1.题目要求两类列表项,如果是需警方介入的crime,就使用一个带联系警方按钮的新布局,因此添加一个新的xml布局文件
1 <?xml version="1.0" encoding="utf-8"?> 2 3 <LinearLayout 4 xmlns:android="http://schemas.android.com/apk/res/android" 5 android:layout_width="match_parent" 6 android:layout_height="wrap_content" 7 android:orientation="vertical" 8 android:padding="8dp"> 9 <TextView 10 android:id="@+id/crime_title" 11 android:layout_width="match_parent" 12 android:layout_height="wrap_content" 13 android:text="Crime Title"/> 14 15 <TextView 16 android:id="@+id/crime_date" 17 android:layout_width="match_parent" 18 android:layout_height="wrap_content" 19 android:text="Crime Date"/> 20 <!--挑战练习:新增一个报警按钮--> 21 <Button 22 android:id="@+id/require_police" 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content" 25 android:text="call 110" 26 android:textAllCaps="false"/> 27 </LinearLayout>
2.在Crime对象里,再添加一个mRequiresPolice实例变量,并且为mRequiresPolice添加响应的getter和setter方法
1 package com.bignerdranch.android.criminalintent.entity; 2 3 import java.util.Date; 4 import java.util.UUID; 5 6 public class Crime { 7 private UUID mId; 8 private String mTitle; 9 private Date mDate; 10 private boolean mSolved; 11 //题目要求的是否叫警察 12 private boolean mRequiresPolice; 13 14 public Crime() { 15 this.mId = UUID.randomUUID(); 16 this.mDate = new Date(); 17 } 18 19 public UUID getmId() { 20 return mId; 21 } 22 23 public String getmTitle() { 24 return mTitle; 25 } 26 27 public void setmTitle(String mTitle) { 28 this.mTitle = mTitle; 29 } 30 31 public Date getmDate() { 32 return mDate; 33 } 34 35 public void setmDate(Date mDate) { 36 this.mDate = mDate; 37 } 38 39 public boolean ismSolved() { 40 return mSolved; 41 } 42 43 public void setmSolved(boolean mSolved) { 44 this.mSolved = mSolved; 45 } 46 47 public boolean ismRequiresPolice() { 48 return mRequiresPolice; 49 } 50 51 public void setmRequiresPolice(boolean mRequiresPolice) { 52 this.mRequiresPolice = mRequiresPolice; 53 } 54 }
3.在CrimeLab中赋值,每10个就是需要警方介入的crime
1 public CrimeLab(Context context) { 2 mCrimes = new ArrayList<>(); 3 for (int i = 0; i < 100; i++) { 4 Crime crime = new Crime(); 5 crime.setmTitle("Crime #" + i); 6 crime.setmSolved(i % 2 == 0); 7 //每隔10个就是需警方介入的crime 8 crime.setmRequiresPolice(i % 10 == 0); 9 mCrimes.add(crime); 10 } 11 }
4.在原本CrimeHolder的基础下新增一个requirePoliceCrimeHolder内部类
1 //定义一个新的requirePoliceCrimeHolder内部类一个CrimeHolder对应一行列表项,对应布局为 list_item_require_crime 2 private class requirePoliceCrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 3 private TextView mTitleTextView; 4 private TextView mDateTextView; 5 private Button mRequirePolice; 6 private Crime mCrime; 7 8 //只要收到一个crime,CrimeHolder就会刷新显示mTitleTextView和mDateTextView 9 private void bind(Crime crime) { 10 mCrime = crime; 11 mTitleTextView.setText(mCrime.getmTitle()); 12 mDateTextView.setText(mCrime.getmDate().toString()); 13 } 14 15 public requirePoliceCrimeHolder(LayoutInflater inflater,ViewGroup parent) { 16 //首先实例化 list_item_require_crime 布局然后传给super()即ViewHolder的构造方法*/ 17 super(inflater.inflate(R.layout.list_item_crime,parent,false)); 18 19 mTitleTextView = (TextView)itemView.findViewById(R.id.crime_title); 20 mDateTextView = (TextView)itemView.findViewById(R.id.crime_date); 21 mRequirePolice = (Button)itemView.findViewById(R.id.require_police); 22 itemView.setOnClickListener(this); 23 } 24 25 @Override 26 public void onClick(View v) { 27 Toast.makeText(getActivity(),"Require Police!",Toast.LENGTH_SHORT).show(); 28 } 29 }
5.适配器CrimeAdapter,现在多了requirePoliceCrimeHolder,适配器就不能专门用泛型接收CrimeHolder了, 在onCreateViewHolder(ViewGroup,int)方法里,基于getItemViewType(int)方法返回的ViewType值,需要返回不同的ViewHolder。
1 public class CrimeAdapter extends RecyclerView.Adapter { 2 private List<Crime> mCrimes; 3 public CrimeAdapter(List<Crime> crimes) { 4 mCrimes = crimes; 5 } 6 //视图类别功能 7 @Override 8 public int getItemViewType(int position) { 9 //真不报警 10 if(mCrimes.get(position).ismRequiresPolice()) { 11 return 1; 12 }else{ 13 return 0; 14 } 15 } 16 @NonNull 17 @Override 18 public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { 19 //先创建LayoutInflater 20 LayoutInflater layoutInflater=LayoutInflater.from(getActivity()); 21 22 //判断上面的i的值判断使用什么布局,即getItemViewType的返回值 23 if (i == 1) 24 return new requirePoliceCrimeHolder(layoutInflater, viewGroup); 25 else 26 return new CrimeHolder(layoutInflater, viewGroup); 27 } 28 29 //需要绑定数据(上下滑动屏幕)时,就会读取当前位置并绑定 30 @Override 31 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 32 if (holder instanceof CrimeHolder) { //instance,如果左侧的对象是右侧类的实例,则返回true 33 Crime crime = mCrimes.get(position); 34 ((CrimeHolder)holder).bind(crime); 35 }else if (holder instanceof requirePoliceCrimeHolder){ 36 Crime crime = mCrimes.get(position); 37 ((requirePoliceCrimeHolder)holder).bind(crime); 38 } 39 } 40 41 @Override 42 public int getItemCount() { 43 return mCrimes.size(); 44 } 45 }
6.运行效果: