我的堆栈真的溢出了,我的意思是目前我的大脑想不出解决以下问题的方法(尽管我经历了很多天的反复试验)。我想做的只是一个用于删除目的的屏幕,例如(http://asset0.cbsistatic.com/cnwk.1d/i/tim/2010/11/18/Foreman_11654166_1073_com.probosoft.masscontactsdelete0_257x386.png)
我有一个这样的列表视图项目的布局(log_view.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp" >
<TextView
android:id="@+id/date_view"
android:gravity="top|left"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true" />
<TextView
android:id="@+id/value_view"
android:gravity="top|left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/date_view"
android:layout_alignParentLeft="true" />
<CheckBox
android:id="@+id/del_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:visibility="gone"
android:focusable="false"
android:focusableInTouchMode="false" />
</RelativeLayout>
这是我的自定义适配器:
class LogViewAdapter extends ArrayAdapter<Log> {
public ArrayList<Boolean> checkList;
private int layoutResourceId;
private List<Log> logList;
Context context;
public LogViewAdapter(Context context, int layoutResourceId, List<Log> data) {
super(context, R.layout.log_view, data);
this.layoutResourceId = layoutResourceId;
this.logList = data;
this.context = context;
checkList = new ArrayList<Boolean>();
for (int i = 0; i < logList.size(); i ++) {
checkList.add(false);
}
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LogHolder logholder = null;
// Unidentified view
if(convertView == null) {
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
convertView = inflater.inflate(layoutResourceId, parent, false);
// Create a new holder
logholder = new LogHolder();
logholder.del_box = (CheckBox)convertView.findViewById(R.id.del_box);
logholder.del_box.setChecked(false);
final int iFinal = position;
logholder.del_box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checkList.set(iFinal, buttonView.isChecked());
}
});
logholder.date_view = (TextView)convertView.findViewById(R.id.date_view);
logholder.value_view = (TextView)convertView.findViewById(R.id.value_view);
convertView.setTag(logholder);
}
// Identified view
else {
logholder = (LogHolder) convertView.getTag();
}
if (null != logList) {
if (null == checkList.get(position)) {
android.util.Log.e("getView", "Checklist null at " + position);
}
//logholder.del_box.setChecked((boolean)checkList.get(position));
logholder.date_view.setText(logList.get(position).date);
logholder.value_view.setText(logList.get(position).value);
}
android.util.Log.e("getView", " at " + position + ", value = " + logholder.value_view.getText().toString());
return convertView;
}
static class LogHolder {
TextView date_view;
TextView value_view;
CheckBox del_box;
}
}
这是我的活动:
public class LoggingActivity extends Activity {
//private EditText edt_name;
//private EditText edt_value;
private List<Log> logList;
private LogViewAdapter lw_adapter;
private ListView listView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.log_list);
//setContentView(android.R.layout.simple_list_item_multiple_choice);
logList = loadLog();
listView = (ListView)findViewById(R.id.log_list);
lw_adapter = new LogViewAdapter(this, R.layout.log_view, logList);
//lw_adapter = new LogViewAdapter(this, android.R.layout.simple_list_item_multiple_choice, logList);
listView.setAdapter(lw_adapter);
}
/** implements for the MENU soft-key. Android 2.3.x */
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.log_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// IMPORTANT: listView.getChildAt(index) will only return the
// VISIBLE views in our current screen
if (null == listView) {
android.util.Log.e("onOptionsItemSelected", "list view null");
return true;
}
for (int i = 0; i < listView.getChildCount(); i++) {
if (null == listView.getChildAt(i)) continue;
CheckBox cb = (CheckBox) listView.getChildAt(i).findViewById(R.id.del_box);
if (null == cb) {
android.util.Log.e("CB", "CheckBox at i = " + i + " null");
return true;
}
final int iFinal = i + listView.getFirstVisiblePosition();
cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
listView.setItemChecked(iFinal, buttonView.isChecked());
lw_adapter.checkList.set(iFinal, buttonView.isChecked());
}
});
SparseBooleanArray selectedItems = listView.getCheckedItemPositions();
for (int j = 0; j < selectedItems.size(); j++) {
if (selectedItems.get(j)) {
android.util.Log.e("CHECKED", "Row "+ j + ", value = " + logList.get(j).value);
}
else {
android.util.Log.e("CHECKED", "Row "+ j + " not checked");
}
}
cb.setVisibility(View.VISIBLE);
cb.setEnabled(true);
}
File folder = new File(Environment.getExternalStorageDirectory(), "50802566/logs");
// Handle item selection
switch (item.getItemId()) {
case R.id.log_sort:
Collections.sort(logList, Log.COMPARE_BY_VALUE);
lw_adapter.notifyDataSetChanged();
return true;
case R.id.log_del:
for (int i = 0; i < logList.size(); i++) {
if (null == lw_adapter.checkList.get(i)) {
android.util.Log.e("DEL", "checklist["+ i + "] = null");
continue;
}
if (true == lw_adapter.checkList.get(i)) {
// Delete correlative xml file
Date date = null;
try {
date = new SimpleDateFormat("dd/MM/yyyy - HH:mm:ss").parse(logList.get(i).date);
} catch (ParseException e) {
e.printStackTrace();
}
String filename = new SimpleDateFormat("dd_MM_yyyy - HH_mm_ss").format(date) + ".xml";
File toDelete = new File(folder, filename);
if (!toDelete.delete()) {
android.util.Log.e("DEL", "File " + filename + ": not deleted or not existed");
}
// Update the UI
//lw_adapter.remove(logList.get(i));
//lw_adapter.checkList.remove(i);
logList.set(i, null);
lw_adapter.checkList.set(i, null);
android.util.Log.e("DEL", "Deleted " + i + ", size now = " + logList.size());
}
}
for (int i = 0; i < logList.size(); i ++) {
if (null == logList.get(i)) {
logList.remove(i);
lw_adapter.checkList.remove(i);
}
}
lw_adapter.notifyDataSetChanged();
// Refresh the checklist
for (int i = 0; i < lw_adapter.checkList.size(); i ++) {
lw_adapter.checkList.set(i, false);
}
for (int i = 0; i < listView.getChildCount(); i++) {
if (null == listView.getChildAt(i)) continue;
CheckBox cb = (CheckBox) listView.getChildAt(i).findViewById(R.id.del_box);
cb.setChecked(false);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private ArrayList<Log> loadLog() {
/** Access folder "my_logs" in external memory */
File baseDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator +
"50802566/logs");
if (!baseDir.exists()) { baseDir.mkdirs(); }
File[] list_file = baseDir.listFiles();
/** For internal memory */
//File[] list_file = this.getFilesDir().listFiles();
for (int i = 0; i < list_file.length; i ++) {
//android.util.Log.e("PRINTLN", list_file[i].getPath());
}
int l = list_file.length;
ArrayList<Log> list = new ArrayList<Log>();
while (l-- > 0) {
File file = list_file[l];
FileInputStream fin = null;
LogReader logr = new LogReader();
try {
fin = new FileInputStream(file);
list.add(list_file.length - l - 1, logr.read(fin));
fin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return list;
}
}
问题是:
我无法跟踪每个 CheckBox 的布尔值。例如,如果我对 logList(我的数据库)进行排序,然后将“notifyDataSetChanged”添加到 listView,但我的 checkList(包含 CheckBox 的布尔值)仍然相同,并且会发生奇怪的事情。如何将一个列表的所有排序操作完全应用于另一个列表?(IMO,“同步排序”或类似的东西......)
如您所见,我尝试通过从其行中获取 del_box(我的 CheckBox id)来解决#1,然后将其“OnCheckedChangeListener”设置为进行分配(一旦检查,它将更新布尔列表中的相对值“清单”)。但是奇怪的事情又发生了:
- 当检查一行并向下滚动时,我看到另一个已检查。
- 向后滚动时,前一个选中的...未选中(当然是自动的)。
也许适配器正在重新使用错误的视图/值,但我不知道如何让它做正确的事情......>“<
您的帮助和指导很棒。你的示例代码对我来说非常完美......(我现在真的很累>“<)
更新:
我找到了一种方法来(以某种方式)解决它,但也许它违反了 Android 的 API 行为......如果你有更安全的解决方案,请告诉我^^
正如我在第二条评论中提到的,这里是代码:
@Override
public void onCheckedChanged(CompoundButton cb, boolean isChecked) {
int graphicalPos = -1;
// This is top view on the screen for sure
if (((View)cb.getParent()).getTop() < 0) {
graphicalPos = 0;
}
else if (((View)cb.getParent()).getTop() == 0) {
graphicalPos = (int) (((View)cb.getParent()).getTop() / ((View)cb.getParent()).getHeight());
}
else if (((View)cb.getParent()).getTop() > 0) {
graphicalPos = (int) (((View)cb.getParent()).getTop() / ((View)cb.getParent()).getHeight());
if (listView.getChildAt(0).getTop() < 0) {
graphicalPos = graphicalPos + 1;
}
else {
android.util.Log.e("NOT PLUS", "First Top = " + listView.getChildAt(0).getTop());
}
}
int dataPos = graphicalPos + listView.getFirstVisiblePosition();
lw_adapter.checkList.set(dataPos, isChecked);
android.util.Log.e("onCheckedChanged", "Checked row " + dataPos + ", graphicalPos = " + graphicalPos + ", top = " + ((View)cb.getParent()).getTop() + ", firstVisible = " + listView.getFirstVisiblePosition());
}