写在前面:
欢迎所有人给我提出任何意见和建议
请注意每一次的程序都是没有承接之前的挑战练习
如果有疑问或者意见的可以在下方评论
谢谢!
由于不经常上线,此处留下我的QQ:623614154 欢迎共同探讨问题
下载区:
第8章挑战练习–>Link
后续还有其他方式提供没有积分的小伙伴下载
目录
挑战练习8.8:RecyclerView ViewType
请在RecyclerView中创建两类列表项:一般性crime,以及需警方介入的crime。
要完成这个挑战,你需要用到RecyclerView.Adapter的视图类别功能(view type)。在Crime对象里,再添加一个mRequiresPolice实例变量,使用它并借助getItemViewType(int)方法
(developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)),确定该加载哪个视图到CrimeAdapter。
在onCreateViewHolder(ViewGroup, int)方法里,基于getItemViewType(int)方法返
回的viewType值,需要返回不同的ViewHolder。如果是一般性crime,就仍然使用原始布局;如果是需警方介入的crime,就使用一个带联系警方按钮的新布局。
- 题目太长,不想看的话,简单解释,就是部分需要警方介入的罪犯,给一个按钮报警。
step 1:添加list_item_police_crime.xml
- 此举是为了添加一个新的布局,预览图长这样↓(可以自己命名,但是要对应上)
- 代码(list_item_police_crime.xml)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="7">
<TextView
android:id="@+id/crime_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Crime Title"
/>
<TextView
android:id="@+id/crime_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Crime Date"/>
</LinearLayout>
<Button
android:id="@+id/call_police"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="40dp"
android:padding="0dp"
android:layout_marginTop="0dp"
android:text="联系警察"/>
</android.support.v7.widget.LinearLayoutCompat>
step 2:Crime中添加变量mRequiresPolice
- 如题目所讲的,加入mRequiresPolice,当一个罪犯需要警察的时候,这个变量设置为True
- 代码(Crime.java)
public class Crime {
private boolean mRequiresPolice;//按要求加入变量标记需要警察的
...
public void setSolved(boolean solved) {
mSolved = solved;
}
//下面加入get/set方法
public void setRequiresPolice(boolean requiresPolice) {
mRequiresPolice = requiresPolice;
}
public boolean isRequiresPolice() {
return mRequiresPolice;
}
}
step 3:初始化设置需要警察的Crime
- 既然加入了变量,就应该初始化。此处设置所有
偶数
个的Crime都需要警察(可以不一样,测试到就可以)。 - 代码(CrimeLab.java)
private CrimeLab(Context context){
mCrimes = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Crime crime = new Crime();
crime.setTitle("Crime #" + i);
crime.setSolved(i % 2 == 0);
//第偶数个Crime设置为True
if(i % 2 == 0)
crime.setRequiresPolice(true);
else
crime.setRequiresPolice(false);
mCrimes.add(crime);
}
}
step 4:创建一个新的Holder—PoliceHolder
- 在CrimeListFragment里面新建一个Holder内部类,
容纳新的布局
,名字可以自己取。 - 代码(CrimeListFragment.java)
/**
* 新建一个内部类,类似CrimeHolder
*/
private class PoliceHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TextView mTitleTextView;
private TextView mDateTextView;
private Crime mCrime;
private Button mCallPolice;
public PoliceHolder(LayoutInflater inflater, ViewGroup parent) {
super(inflater.inflate(R.layout.list_item_police_crime, parent, false));
itemView.setOnClickListener(this);
mTitleTextView = (TextView)itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView)itemView.findViewById(R.id.crime_date);
//绑定按钮
mCallPolice = (Button)itemView.findViewById(R.id.call_police);
//点击的时候显示一段文字
mCallPolice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getActivity(),"已经联系了警察了",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onClick(View view) {
Toast.makeText(getActivity(),mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT).show();
}
public void bind(Crime crime){
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
}
}
step 5:利用ViewType判断显示不同布局
- 1. 为了显示不同的布局,首先要判断当前罪犯是否需要警察,所以要isRequiresPolice()检查,如果True那么就是需要的,返回1,否则返回0。
- 代码(CrimeListFragment)
private class CrimeAdapter extends RecyclerView.Adapter {
...
/**
*
* @param position
* @return 返回 1 说明设置了这个罪犯是要警察才行,对应crime里面的是mRequiresPolice==True
* 返回 0 说明设置了这个罪犯是不需要警察,对应crime里面的是mRequriesPolice==false
*/
@Override
public int getItemViewType(int position) {
if(mCrimes.get(position).isRequiresPolice() == true){
return 1;
}
else{
return 0;
}
}
...
}
- 2. 将不同crime绑定对应的holder
- 代码(CrimeListFragment)
private class CrimeAdapter extends RecyclerView.Adapter {
...
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Crime crime = mCrimes.get(position);
//得到ViewType 绑定不同的holder
if(this.getItemViewType(position) == 1) {
((PoliceHolder)holder).bind(crime);
}
else{
((CrimeHolder)holder).bind(crime);
}
}
}
step 6:最重要的一步,根据不同的ViewType新建不同Holder实例
- 这里要将返回类型改为更加通用的RecyclerView.ViewHolder,不能是CrimeHolder了,因为你不确定用哪一个holder显示
- 代码
private class CrimeAdapter extends RecyclerView.Adapter {
...
/**
*
* @return 返回类型改为RecyclerView.ViewHolder
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
//根据getViewType函数里面的设置的viewType的值,调用不同的holder
if(viewType == 1){
return new PoliceHolder(layoutInflater, parent);
}
else{
return new CrimeHolder(layoutInflater, parent);
}
}
@Override
public int getItemCount() {
return mCrimes.size();
}
}
结果
- 我在step3中,设置的第偶数个罪犯是需要联系警察的,所以可以看到,最终结果如下
- 点击联系警察按钮会弹出Toast,That’s It 结束了。