引言
上一篇文章Android进阶——初识万能的RecycleView(一)介绍了下RecycleView的一些知识,以及组成成员所承担的角色和大致的原理流程,接下来就在实际应用中的一起体会吧,先放项目中的效果图直观感受下再一步步的去实现。(单击勾选同时动态获取设备的状态显示并获得对应的时间值,再次单击取消勾选,长按删除,单击自定义时弹出自定义对话框,选择时间之后显示到列表上)
一、实现的核心思想
很明显如果从UI方面去动态改变的话,不是不行,但是很麻烦,而我们知道RecycleView只是提供了一个容器,界面呈现的效果从一定程度来说只是取决于RecycleView.Adapter里创建了什么样的ViewHolder以及填充什么样的数据,所以要实现这个效果只需要考虑去动态更新RecycleView.Adapter,动态去绘制ItemView即可,剩下的逻辑就放在Activity去处理。
二、编码实现
1、使用RecycleView前得先在Android studio里对应的module模块下的gradle脚本引入
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:recyclerview-v7:24.0.0'
}
2、编写RecycleView里item的布局文件和MainActivity的布局文件
RecycleView里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_height="wrap_content"
android:orientation="vertical">
<!--DevDelayActivity 选择时间列表的item-->
<RelativeLayout
android:id="@+id/rl_choose_time"
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
android:padding="6dp">
<TextView
android:id="@+id/tv_delay_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="5分钟"
android:textColor="@color/black" />
<TextView
android:id="@+id/tv_dev_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginRight="33dp"
android:layout_toLeftOf="@+id/iv_check"
android:text="后开启" />
<ImageView
android:id="@+id/iv_check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>
</RelativeLayout>
</LinearLayout>
MainActivity的布局:
<?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:padding="10dp">
<android.support.v7.widget.RecyclerView
android:id="@+id/listv_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="6dp"
android:background="@drawable/shape_listv_bcg"
>
</android.support.v7.widget.RecyclerView>
</LinearLayout>
3、编写RecycleView的Adapter
实现Adapter可以分为几步:
- 新建自己的Adapter类继承自RecyclerView.Adapter《RecyclerView.ViewHolder》 ,根据自己的业务封装对应的Bean
- 实现onCreateViewHolder方法,这个方法的主要作用就是创建初始化对应的ViewHolder,与AdapterView的Adapter中的getView方法类似,但仅仅是创建ViewHolder并未开始填充数据绘制。
- 实现getItemCount返回数据集的size
- 定义自己的ViewHolder 继承自 RecyclerView.ViewHolder,用于缓存item,可以通过弱引用来减少OOM
- 定义Item的接口事件对应的回调接口
package crazymo.train.recycleview.adapter;
import android.content.Context;
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 java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import crazymo.train.recycleview.R;
import crazymo.train.recycleview.bean.MainListItem;
/**
* @auther: Crazy.Mo
* Date: 2016/9/29
* Time:14:36
* Des:MainListView 的Adapter
*/
public class MainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<MainListItem> mList = new ArrayList<>();
private LayoutInflater mLayoutInflater;
private static MainRecycleViewClickListener mListener;
private Context mContext;
public MainAdapter(Context context) {
this.mContext = context;
this.mLayoutInflater = LayoutInflater.from(context);
}
public void setList(List<MainListItem> list) {
mList.clear();
this.mList = list;
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MainViewHolder viewHolder = new MainViewHolder(mLayoutInflater.inflate(R.layout.listv_item_main, parent, false));
viewHolder.setDelayAdapter(this);
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((MainViewHolder) holder).tvDelayTime.setText(mList.get(position).getTime());
((MainViewHolder) holder).tvDevState.setText(mList.get(position).getStateName());
//根据check值动态创建对应的item
if (mList.get(position).getIsCheck() == 1) {
((MainViewHolder) holder).ivCheck.setVisibility(View.VISIBLE);
((MainViewHolder) holder).ivCheck.setBackgroundResource(R.mipmap.selected_icon);
} else {
((MainViewHolder) holder).ivCheck.setVisibility(View.INVISIBLE);
((DelayViewHolder) holder).ivCheck.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
if(mListener!=null){
v.setBackgroundResource(R.mipmap.selected_icon);
}
}
});
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
@Override
public int getItemCount() {
return mList.size();
}
class MainViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.tv_delay_time)
TextView tvDelayTime;
@Bind(R.id.tv_dev_state)
TextView tvDevState;
@Bind(R.id.iv_check)
ImageView ivCheck;
private WeakReference<MainAdapter> ref;
private MainAdapter mainAdapter;
MainViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//执行Item Click事件
mListener.onItemClick(getLayoutPosition());
}
});
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mListener.onItemLongClick(getLayoutPosition());
return true;//这里返回true 就不会在LongClick之后再重复执行onClick
}
});
}
public void setDelayAdapter(MainAdapter adapter) {
if (adapter!=null){
ref = new WeakReference<MainAdapter>(adapter);
}
mainAdapter = ref.get();
}
}
//设置Item事件监听
public void setOnMainRecycleOnClickListener(MainRecycleViewClickListener itemOnClickListener) {
mListener = itemOnClickListener;
}
//定义Item事件接口
public interface MainRecycleViewClickListener {
void onItemClick(int pos);
void onItemLongClick(int pos);
}
}
package crazymo.train.recycleview.bean:
/**
* @auther: Crazy.Mo
* Date: 2016/9/29
* Time:14:23
* Des:
*/
public class MainListItem {
private String time;
private String stateName;
private int isCheck;//0,未选中;1选中
public MainListItem(String time, String stateName, int isCheck) {
this.time = time;
this.stateName = stateName;
this.isCheck = isCheck;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getStateName() {
return stateName;
}
public void setStateName(String stateName) {
this.stateName = stateName;
}
public int getIsCheck() {
return isCheck;
}
public void setIsCheck(int isCheck) {
this.isCheck = isCheck;
}
}
4、实现Activity
- 实现RecycleView.Adapter的接口,用于接收处理Item事件
- 在对应的生命周期方法中完成Adapter、RecycleView的初始化
- 处理RecycleView.Adapter的事件,完成相关的业务逻辑
package crazymo.train.recycleview;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import crazymo.train.recycleview.adapter.DividerItemDecoration;
import crazymo.train.recycleview.adapter.MainAdapter;
import crazymo.train.recycleview.bean.MainListItem;
public class MainActivity extends Activity implements MainAdapter.MainRecycleViewClickListener{
private static final String TAG ="CrazyMo" ;
@Bind(R.id.listv_main)
RecyclerView listvMain;
private MainAdapter adapter;
private List<MainListItem> list = new ArrayList<>();
String deviceStatus="后开启";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
init();
}
private void init(){
initRecycleView();
}
private void initRecycleView(){
initListData();
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//设置item垂直布局可以垂直滑动,也可设置为水平布局可以水平滑动
adapter = new MainAdapter(this);
if (adapter != null) {
adapter.setList(list);
adapter.setOnMainRecycleOnClickListener(this);
listvMain.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
listvMain.setLayoutManager(layoutManager);
listvMain.setHasFixedSize(true);
listvMain.setAdapter(adapter);
}
}
private void initListData(){
list.add(new MainListItem("5分钟","",0));
list.add(new MainListItem("10分钟","",0));
list.add(new MainListItem("15分钟","",0));
list.add(new MainListItem("20分钟","",0));
list.add(new MainListItem("25分钟","",0));
list.add(new MainListItem("30分钟","",0));
list.add(new MainListItem("自定义","",0));
}
@Override
public void onItemClick(int pos){
for(int i=0;i<list.size();i++){
//首先定位到需要修改数据项
if(i==pos && pos!=6){
if(list.get(pos).getIsCheck()==1){
list.get(pos).setIsCheck(0);
list.get(pos).setStateName("");
}
else {
list.get(pos).setIsCheck(1);
list.get(pos).setStateName(deviceStatus);
}
}
else if(i==pos && pos==6){
if(list.get(pos).getIsCheck()==1){
list.get(pos).setIsCheck(0);
list.get(pos).setTime("自定义");
list.get(pos).setStateName("");
}else {
list.get(pos).setIsCheck(1);
list.get(pos).setStateName(deviceStatus);
}
}else{
list.get(i).setIsCheck(0);
list.get(i).setStateName("");
}
}
adapter.notifyDataSetChanged();
Log.e(TAG, "onItemClick: " );
}
@Override
public void onItemLongClick(int pos) {
//实现RecycleView的Item 长按击触发的方法
list.remove(pos);
adapter.notifyItemRangeRemoved(0,pos);
Log.e(TAG, "onItemLongClick: " );
}
}
运行结果(简化了很多效果,同时也为了突出显示分割线,故意做得这么不和谐)