ListView 中的每一項添加一個checkbox複選框,實作複選功能。
包含ListView的布局檔案
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".RecvLoadActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/activity_load_mian_paddingBotton">
<CheckBox
android:id="@+id/cbFcrq"
android:checked="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發車日期:" />
<EditText
android:id="@+id/etFcrq"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:hint="格式 2015-8-8"
android:inputType="date"
android:singleLine="true" />
<TextView
android:id="@+id/btnGetDate"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/button_normal_bg_selector"
android:gravity="center_vertical"
android:text="選擇"
android:textColor="@color/white" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/activity_load_mian_paddingBotton">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="車 牌 号:" />
<EditText
android:id="@+id/etLoadCph"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:hint="例如輸入2352再選擇"
android:singleLine="true" />
<TextView
android:id="@+id/btnSelectCar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/button_normal_bg_selector"
android:gravity="center_vertical"
android:text="選擇"
android:textColor="@color/white" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/lightgray" />
</LinearLayout>
<ListView
android:id="@+id/listViewLoad"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:dividerHeight="1px"/>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:background="@color/gray"
android:layout_height="wrap_content">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/blue" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingRight="6dp"
android:paddingLeft="6dp"
android:orientation="horizontal"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一接駁網點:" />
<Spinner
android:id="@+id/spinnerNextNet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/lightgray" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="6dp"
android:paddingLeft="6dp"
android:orientation="horizontal">
<Button
android:id="@+id/btnQuery"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_bottom_bg_selector"
android:text="查詢"
android:textColor="@color/blue"
/>
<Button
android:id="@+id/btnRecvLoad"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/button_bottom_bg_selector"
android:gravity="center"
android:layout_weight="1"
android:text="接收并快捷裝車"
android:textColor="@color/blue"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvTotalCount"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="0"
android:textSize="17sp"
android:textColor="#F00"/>
<CheckBox
android:id="@+id/cbAll"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="全選"
android:gravity="center_vertical"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
清單每一項的布局
完整的item.xml檔案
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:baselineAligned="false"
android:padding="4dp" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tvBillNo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="運單号aaaaaaaaaa"
android:textColor="#F00"
android:textStyle="bold" />
<TextView
android:id="@+id/tvBillFlowStatus"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="流轉狀态"
android:gravity="center"
android:layout_weight="1"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvTerminal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:text="目的地" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="2dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="發車:"
android:textStyle="bold"
/>
<TextView
android:id="@+id/tvDepartTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2015-08-31 10:45" />
<TextView
android:id="@+id/tvCph"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="車牌12345"
android:gravity="center"
android:layout_weight="1"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvCalcCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:text="件數" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical" >
<CheckBox
android:padding="6dp"
android:id="@+id/cbItem"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical" />
</LinearLayout>
</LinearLayout>
核心的Adapter繼承BaseAdapter
public class RecvLoadAdapter extends BaseAdapter {
private OnItemCheckListener mOnItemCheckListener;
private List<Bill> mList;
private LayoutInflater mInflater;
public Set<Long> mCheckedSet = new HashSet<>();//儲存邏輯運單id,此集合用來訓示勾選框的狀态邏輯
public RecvLoadAdapter(Context context,OnItemCheckListener onItemCheckListener, List<Bill> data){
mOnItemCheckListener = onItemCheckListener;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mList = data;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v ;
if(convertView == null){
v = mInflater.inflate(R.layout.item_recv_load,parent,false);
}else{
v = convertView;
}
//填充view
Bill item = (Bill) getItem(position);
String date = item.getL_DepartDate();
if(date!=null){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd",Locale.getDefault());
try {
String fcsj = sdf.format(sdf.parse(date))+" "+item.getL_DepartTime();
((TextView)v.findViewById(R.id.tvDepartTime)).setText(fcsj);
} catch (ParseException e) {
e.printStackTrace();
}
}
((TextView)v.findViewById(R.id.tvTerminal)).setText(item.getB_Terminal());
((TextView)v.findViewById(R.id.tvCalcCount)).setText(String.format(Locale.getDefault(),"%d件",item.getB_CalcCount()));
((TextView)v.findViewById(R.id.tvBillNo)).setText(item.getB_No());
((TextView)v.findViewById(R.id.tvCph)).setText(item.getL_CarPlateNo());
((TextView)v.findViewById(R.id.tvBillFlowStatus)).setText(item.getB_FlowStatusText());
//添加删除按鈕點選事件
//final int p = position;
final long p = item.getBillId();
CheckBox cbItem = v.findViewById(R.id.cbItem);
cbItem.setChecked(mCheckedSet.contains(p));
cbItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mCheckedSet.contains(p)){
mCheckedSet.remove(p);
mOnItemCheckListener.onItemCheckClick(p,false);//unchecked事件
}else{
mCheckedSet.add(p);
mOnItemCheckListener.onItemCheckClick(p,true);//checked事件
}
}
});
return v;
}
/**
* 當主界面點選全選按鈕時觸發
* @param isChecked
*/
public void onCheckAllClick(boolean isChecked){
if(isChecked){
for(Bill b: mList){
mCheckedSet.add(b.getBillId());
}
}else{
mCheckedSet.clear();
}
notifyDataSetChanged();
}
public interface OnItemCheckListener{
/**
* 某一項複選框check事件
* @param id bill ID
* @param checked true表示選中事件,false表示不選中事件
*/
void onItemCheckClick(long id,boolean checked);
}
}
使用ListView的Fragment或者Activity
public class RecvLoadActivity extends Activity implements RecvLoadAdapter.OnItemCheckListener {
private CheckBox cbFcrq,cbAll;
private ListView mListView;
private List<Bill> mList;
private RecvLoadAdapter mAdapter;
private TextView tvTotalCount;//已checked的數量
private View btnQuery;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recv_load);
//初始化清單
mList = new ArrayList<>();
mAdapter = new RecvLoadAdapter(this,this,mList);
mListView.setAdapter(mAdapter);
//全選
cbAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isChecked = cbAll.isChecked();
mAdapter.onCheckAllClick(isChecked);
tvTotalCount.setText(String.valueOf(mAdapter.mCheckedSet.size() ));
}
});
}
//單擊某項,勾選之
@Override
public void onItemCheckClick(long id, boolean checked) {
if (checked) {
if (mAdapter.mCheckedSet.size() == mList.size()) {
cbAll.setChecked(true);
}
} else {
cbAll.setChecked(false);
}
tvTotalCount.setText(String.valueOf( mAdapter.mCheckedSet.size()));
}
核心的實作思路:在Adapter中用一個Set儲存每個勾選的項的ID(最好用填充每個項的對象的唯一辨別),在getView()方法中,關鍵的幾何實作代碼如下:
final long p = item.getBillId();
CheckBox cbItem = (CheckBox) v.findViewById(R.id.cbItem);
cbItem.setChecked(mCheckedSet.contains(p));
cbItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mCheckedSet.contains(p)){
mCheckedSet.remove(p);
mOnItemCheckListener.onItemCheckClick(p,false);//unchecked事件
}else{
mCheckedSet.add(p);
mOnItemCheckListener.onItemCheckClick(p,true);//checked事件
}
}
});
請勿使用changeListener。
mOnItemCheckListener 是回調接口,用于在Ativity中同步儲存資料。
在Activity中實作全選複選框功能:
//全選
cbAll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isChecked = cbAll.isChecked();
mAdapter.onCheckAllClick(isChecked);
tvTotalCount.setText(String.valueOf(mAdapter.mCheckedSet.size() ));
}
});
這裡也用到了回調函數onCheckAllClick,該函數在Adapter中聲明為public即可,當主界面點選全選按鈕時更新Adapter界面:
public void onCheckAllClick(boolean isChecked){
if(isChecked){
for(Bill b: mList){
mCheckedSet.add(b.getBillId());
}
}else{
mCheckedSet.clear();
}
notifyDataSetChanged();
}
總結:最關鍵的地方是用了一個Set來儲存已checked的項,用于在getView重繪時正确辨別checkbox的狀态而不至于錯亂顯示問題。