经过这几天的研究终于把这个需求写好了,虽然网上很多,自己在写的时候还是遇到很多问题,在此记录下来。
效果图:
进去就是第一个界面,为了简单,我就写个循环模拟数据。长按ListView的一项出现右图那个界面。
我就直接写代码让后解释一下:
这个是主布局:在这里引用了几个style,在这里就不贴出来了,下面的一行默认是不显示的,当长按ListView的item时显示出来。可以点击最后面的链接下载全部的代码。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_edit_bar"></ListView>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_below="@+id/lv"
android:background="@color/color_gray"/>
<LinearLayout
android:id="@+id/ll_edit_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:background="@color/color_white"
android:orientation="horizontal"
android:translationZ="10dp"
android:layout_alignParentBottom="true"
android:visibility="gone">
<LinearLayout
android:id="@+id/ll_cancel"
style="@style/EditBarItemStyle">
<ImageView
style="@style/EditBarImageViewStyle"
android:src="@drawable/ic_cancel" />
<TextView
style="@style/EditBarTextViewStyle"
android:text="@string/str_cancel" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_delete"
style="@style/EditBarItemStyle">
<ImageView
style="@style/EditBarImageViewStyle"
android:layout_height="17dp"
android:src="@drawable/ic_delete_blue" />
<TextView
style="@style/EditBarTextViewStyle"
android:text="@string/str_delete" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_inverse"
style="@style/EditBarItemStyle">
<ImageView
style="@style/EditBarImageViewStyle"
android:src="@drawable/ic_inverse" />
<TextView
style="@style/EditBarTextViewStyle"
android:text="@string/str_inverse" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_select_all"
style="@style/EditBarItemStyle">
<ImageView
style="@style/EditBarImageViewStyle"
android:src="@drawable/ic_select_all" />
<TextView
style="@style/EditBarTextViewStyle"
android:text="@string/str_select_all" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
ListView的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="match_parent"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_data"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginLeft="15dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="111111"
android:textColor="@color/colorPrimary" />
<CheckBox
android:id="@+id/chb_select_way_point"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:buttonTint="@color/color_blue"
android:layout_marginRight="20dp"
android:clickable="false"
android:focusable="false"
android:visibility="gone" />
</LinearLayout>
主界面的Activity,这里也是重点,主要就是设一个选中的List存放选中的数据,还有一个SparseBooleanArray对象用于存储每一项的选中状态,SparseBooleanArray也是一个Map,但这个性能要好点。剩下的就不说了,我在代码里写的注释比较详细。
package com.example.f.me1_listview_checkbox;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ListView lvData;
private LinearLayout mLlEditBar;//控制下方那一行的显示与隐藏
private MyAdapter adapter;
private List<String> mData = new ArrayList<>();//所有数据
private List<String> mCheckedData = new ArrayList<>();//将选中数据放入里面
private SparseBooleanArray stateCheckedMap = new SparseBooleanArray();//用来存放CheckBox的选中状态,true为选中,false为没有选中
private boolean isSelectedAll = true;//用来控制点击全选,全选和全不选相互切换
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
adapter = new MyAdapter(MainActivity.this, mData, stateCheckedMap);
lvData.setAdapter(adapter);
setOnListViewItemClickListener();
setOnListViewItemLongClickListener();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_cancel:
cancel();
break;
case R.id.ll_delete:
delete();
break;
case R.id.ll_inverse:
inverse();
break;
case R.id.ll_select_all:
selectAll();
break;
}
}
private void cancel() {
setStateCheckedMap(false);//将CheckBox的所有选中状态变成未选中
mLlEditBar.setVisibility(View.GONE);//隐藏下方布局
adapter.setShowCheckBox(false);//让CheckBox那个方框隐藏
adapter.notifyDataSetChanged();//更新ListView
}
private void delete() {
if (mCheckedData.size() == 0) {
Toast.makeText(MainActivity.this, "您还没有选中任何数据!", Toast.LENGTH_SHORT).show();
return;
}
final CustomDialog dialog = new CustomDialog(this);
dialog.show();
dialog.setHintText("是否删除?");
dialog.setLeftButton("取消", new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.setRightButton("确定", new View.OnClickListener() {
@Override
public void onClick(View v) {
beSureDelete();
dialog.dismiss();
}
});
}
private void beSureDelete() {
mData.removeAll(mCheckedData);//删除选中数据
setStateCheckedMap(false);//将CheckBox的所有选中状态变成未选中
mCheckedData.clear();//清空选中数据
adapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
}
/**
* 反选就是stateCheckedMap的值为true时变为false,false时变成true
* */
private void inverse() {
mCheckedData.clear();
for (int i = 0; i < mData.size(); i++) {
if (stateCheckedMap.get(i)) {
stateCheckedMap.put(i, false);
} else {
stateCheckedMap.put(i, true);
mCheckedData.add(mData.get(i));
}
lvData.setItemChecked(i, stateCheckedMap.get(i));//这个好行可以控制ListView复用的问题,不设置这个会出现点击一个会选中多个
}
adapter.notifyDataSetChanged();
}
private void selectAll() {
mCheckedData.clear();//清空之前选中数据
if (isSelectedAll) {
setStateCheckedMap(true);//将CheckBox的所有选中状态变成选中
isSelectedAll = false;
mCheckedData.addAll(mData);//把所有的数据添加到选中列表中
} else {
setStateCheckedMap(false);//将CheckBox的所有选中状态变成未选中
isSelectedAll = true;
}
adapter.notifyDataSetChanged();
}
private void setOnListViewItemClickListener() {
lvData.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
updateCheckBoxStatus(view, position);
}
});
}
/**
* 如果返回false那么click仍然会被调用,,先调用Long click,然后调用click。
* 如果返回true那么click就会被吃掉,click就不会再被调用了
* 在这里click即setOnItemClickListener
*/
private void setOnListViewItemLongClickListener() {
lvData.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
mLlEditBar.setVisibility(View.VISIBLE);//显示下方布局
adapter.setShowCheckBox(true);//CheckBox的那个方框显示
updateCheckBoxStatus(view, position);
return true;
}
});
}
private void updateCheckBoxStatus(View view, int position) {
MyAdapter.ViewHolder holder = (MyAdapter.ViewHolder) view.getTag();
holder.checkBox.toggle();//反转CheckBox的选中状态
lvData.setItemChecked(position, holder.checkBox.isChecked());//长按ListView时选中按的那一项
stateCheckedMap.put(position, holder.checkBox.isChecked());//存放CheckBox的选中状态
if (holder.checkBox.isChecked()) {
mCheckedData.add(mData.get(position));//CheckBox选中时,把这一项的数据加到选中数据列表
} else {
mCheckedData.remove(mData.get(position));//CheckBox未选中时,把这一项的数据从选中数据列表移除
}
adapter.notifyDataSetChanged();
}
private void initView() {
lvData = (ListView) findViewById(R.id.lv);
mLlEditBar = findViewById(R.id.ll_edit_bar);
findViewById(R.id.ll_cancel).setOnClickListener(this);
findViewById(R.id.ll_delete).setOnClickListener(this);
findViewById(R.id.ll_inverse).setOnClickListener(this);
findViewById(R.id.ll_select_all).setOnClickListener(this);
lvData.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}
private void initData() {
for (int i = 0; i < 1000; i++) {
mData.add("第" + i + "项");
}
setStateCheckedMap(false);
}
/**
* 设置所有CheckBox的选中状态
* */
private void setStateCheckedMap(boolean isSelectedAll) {
for (int i = 0; i < mData.size(); i++) {
stateCheckedMap.put(i, isSelectedAll);
lvData.setItemChecked(i, isSelectedAll);
}
}
@Override
public void onBackPressed() {
if (mLlEditBar.getVisibility() == View.VISIBLE) {
cancel();
return;
}
super.onBackPressed();
}
}
最后就是ListView的Adapter了,这里面也很简单,主要的几个地方我都写注释了。
package com.example.f.me1_listview_checkbox;
import android.content.Context;
import android.support.v7.widget.AppCompatCheckBox;
import android.util.SparseBooleanArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by yangms on 2018/7/16.
*/
public class MyAdapter extends BaseAdapter {
List<String> data = new ArrayList<>();
private Context mContext;
ViewHolder holder;
private boolean isShowCheckBox = false;//表示当前是否是多选状态。
private SparseBooleanArray stateCheckedMap = new SparseBooleanArray();//用来存放CheckBox的选中状态,true为选中,false为没有选中
public MyAdapter(Context context, List<String> data, SparseBooleanArray stateCheckedMap) {
this.data = data;
mContext = context;
this.stateCheckedMap = stateCheckedMap;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(final int position, View convertView, ViewGroup viewGroup) {
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(mContext, R.layout.item, null);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.checkBox = (AppCompatCheckBox) convertView.findViewById(R.id.chb_select_way_point);
holder.mTvData = convertView.findViewById(R.id.tv_data);
showAndHideCheckBox();//控制CheckBox的那个的框显示与隐藏
holder.mTvData.setText(data.get(position));
holder.checkBox.setChecked(stateCheckedMap.get(position));//设置CheckBox是否选中
return convertView;
}
public class ViewHolder {
public TextView mTvData;
public AppCompatCheckBox checkBox;
}
private void showAndHideCheckBox() {
if (isShowCheckBox) {
holder.checkBox.setVisibility(View.VISIBLE);
} else {
holder.checkBox.setVisibility(View.GONE);
}
}
public boolean isShowCheckBox() {
return isShowCheckBox;
}
public void setShowCheckBox(boolean showCheckBox) {
isShowCheckBox = showCheckBox;
}
}
链接地址:https://download.youkuaiyun.com/download/ymszzu/10568545