项目开发中经常会遇到 ListView +CheckBox 结合使用的场景,比如 手机应用程序管理程序 中的卸载功能,需要让用户去 勾选 要卸载的 应用程序,点击 即可进行批量卸载。等等这样的例子很多,这里不一一列举了。直接看要实现的效果吧
未编辑状态
编辑状态
编辑完成
下面是源码
主界面 布局
<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" tools:context=".MainActivity" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/light_grey" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title"/> <Button android:id="@+id/bt_edit" android:layout_width="60dp" android:layout_height="30dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:background="@color/blue" android:text="@string/edit" android:textColor="@color/white" /> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@+id/mListView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="@android:color/transparent" android:divider="@drawable/tbar_line" android:dividerHeight="2dp" /> </LinearLayout> </LinearLayout>
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="wrap_content" > <CheckBox android:id="@+id/cb_op" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="5dp" android:visibility="gone"/> <RelativeLayout android:id="@+id/rl_content" android:layout_width="match_parent" android:layout_height="55dp"> <ImageView android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_alignParentTop="true" android:layout_marginLeft="28dp" android:contentDescription="@string/app_name" android:scaleType="fitXY" android:src="@drawable/line_vertical"/> <ImageView android:id="@+id/iv_app_icon" android:layout_width="40dp" android:layout_height="30dp" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:contentDescription="@string/app_name" android:src="@drawable/ic_launcher"/> <TextView android:id="@+id/tv_appName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_toRightOf="@id/iv_app_icon" android:ellipsize="end" android:maxEms="9" android:singleLine="true" android:text="飓风营救" android:textColor="@color/black" android:textSize="18sp" /> <TextView android:id="@+id/tv_app_size" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_appName" android:layout_marginTop="5dp" android:layout_toRightOf="@id/iv_app_icon" android:text="大小:24.5M" android:textColor="@color/light_grey" android:textSize="13sp" /> <TextView android:id="@+id/tv_app_producer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignTop="@id/tv_appName" android:layout_marginRight="20dp" android:ellipsize="end" android:maxEms="4" android:singleLine="true" android:text="暴雪" android:textColor="@color/black" android:textSize="16sp" /> <TextView android:id="@+id/tv_app_download" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignTop="@id/tv_app_size" android:layout_below="@id/tv_app_producer" android:layout_marginRight="20dp" android:text="150000" android:textColor="@color/light_grey" android:textSize="13sp" /> </RelativeLayout> </RelativeLayout>
MainActivity.java
package com.example.listcheckbox; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.RelativeLayout.LayoutParams; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { List<AppInfo> mList = new ArrayList<AppInfo>(); private AppInfoAdapter mAdapter; private boolean isOP; private Button bt_edit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buildAppData(); findView(); } private void findView() { bt_edit = (Button) findViewById(R.id.bt_edit); ListView mListView = (ListView) findViewById(R.id.mListView); mAdapter = new AppInfoAdapter(getApplicationContext()); mListView.setAdapter(mAdapter); bt_edit.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_edit: isOP = !isOP; removeCheckItem(); if (isOP) { bt_edit.setText("完成"); } else { bt_edit.setText("编辑"); } mAdapter.setOP(isOP); mAdapter.notifyDataSetChanged(); break; default: break; } } private void removeCheckItem() { List<AppInfo> checkedList = new ArrayList<AppInfo>(); List<AppInfo> unCheckedList = new ArrayList<AppInfo>(); if ("完成".equals(bt_edit.getText())) { for (AppInfo ai : mList) { if (ai.isChecked()) { checkedList.add(ai); } else { unCheckedList.add(ai); } } System.out.println("check list:" + checkedList.size()); System.out.println("uncheck list:" + unCheckedList.size()); mList.clear(); mList.addAll(unCheckedList); //同步数据库,物理删除 // syncFavoriteTable(checkedList); } } private void buildAppData() { for (int i = 0; i < 20; i++) { AppInfo ai = new AppInfo(); ai.setAppName("QQ2013 " + i); ai.setAppProducer("腾讯科技 " + i); ai.setAppDownload(150000000 + "" + i + " 次"); ai.setAppSize("14." + i + " M"); mList.add(ai); } } private class AppInfoAdapter extends BaseAdapter { private Context ctx; private LayoutInflater inflater; private boolean isOP; public AppInfoAdapter(Context ctx) { this.ctx = ctx; inflater = (LayoutInflater) ctx .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public void setOP(boolean isOP) { this.isOP = isOP; } @Override public int getCount() { return mList == null ? 0 : mList.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return mList.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder holder; if (convertView == null) { view = inflater.inflate(R.layout.app_item, null); holder = new ViewHolder(); holder.cb_op = (CheckBox) view.findViewById(R.id.cb_op); holder.rl_content = (RelativeLayout) view .findViewById(R.id.rl_content); holder.iv_app_icon = (ImageView) view .findViewById(R.id.iv_app_icon); holder.tv_appName = (TextView) view .findViewById(R.id.tv_appName); holder.tv_app_size = (TextView) view .findViewById(R.id.tv_app_size); holder.tv_app_producer = (TextView) view .findViewById(R.id.tv_app_producer); holder.tv_app_download = (TextView) view .findViewById(R.id.tv_app_download); view.setTag(holder); } else { view = convertView; holder = (ViewHolder) view.getTag(); } if (isOP) { holder.cb_op.setVisibility(View.VISIBLE); RelativeLayout.LayoutParams lps = (LayoutParams) holder.rl_content .getLayoutParams(); lps.leftMargin = ctx.getResources().getDimensionPixelSize( R.dimen.app_item_content_margin); } else { holder.cb_op.setVisibility(View.GONE); RelativeLayout.LayoutParams lps = (LayoutParams) holder.rl_content .getLayoutParams(); lps.leftMargin = 0; } final AppInfo ai = mList.get(position); if (ai.isChecked()) { holder.cb_op.setChecked(true); } else { holder.cb_op.setChecked(false); } holder.tv_appName.setText(ai.getAppName()); holder.tv_app_size.setText(ai.getAppSize()); holder.tv_app_producer.setText(ai.getAppProducer()); holder.tv_app_download.setText(ai.getAppDownload()); holder.cb_op.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { boolean isCheck = ai.isChecked(); ai.setChecked(!isCheck); } }); return view; } } static class ViewHolder { CheckBox cb_op; RelativeLayout rl_content; ImageView iv_app_icon; TextView tv_appName; TextView tv_app_size; TextView tv_app_producer; TextView tv_app_download; } }
这里没有用一个 Map来保存 被选中的item id,而是直接在 AppInfo中定义一个 isChecked 变量来记录,个人觉得这么做更简单一点。
工程源码下载
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
如果想要 点击 item的话,也能选中 ,只需要稍作修改即可
<CheckBox android:id="@+id/cb_op" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="5dp" android:focusable="false" android:focusableInTouchMode="false" android:clickable="false" android:visibility="gone"/>
给CheckBox 加上以下三个属性:
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
由于checkbox的点击事件优先级比listview的高,所以要添加android:focusable="false"属性,使得checkbox初始的时候没有获取焦点。
另外这里是点击ListView的item控制checkbox的状态改变,也就是让item接收clik事件,所以需要加上android:focusableInTouchMode="false"这一属性。
然后给ListView注册 item点击事件即可
private void findView() { bt_edit = (Button) findViewById(R.id.bt_edit); ListView mListView = (ListView) findViewById(R.id.mListView); mAdapter = new AppInfoAdapter(getApplicationContext()); mListView.setAdapter(mAdapter); //设置点击事件 mListView.setOnItemClickListener(this); bt_edit.setOnClickListener(this); } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { AppInfo ai = mList.get(arg2); boolean isCheck = ai.isChecked(); ai.setChecked(!isCheck); //更新UI mAdapter.notifyDataSetChanged(); }
OK,这样点击 item也可以选中了,整个代码我就不上传了,自己照着修改一下就好啦