Android onlistclick切换listview行高导致多重更改
情况: 我的应用程序包含一个ToDo列表样式的listview(每行有一个复选框)。listview行由两个垂直排列的文本视图构成。最上面的文本是标题,最下面的是描述,但是描述是隐藏的(View.GONE)。使用ListActivities onListItemClick方法,我可以设置按下行的高度和可见性Android onlistclick切换listview行高导致多重更改,android,listview,android-listview,toggle,Android,Listview,Android Listview,Toggle,情况: 我的应用程序包含一个ToDo列表样式的listview(每行有一个复选框)。listview行由两个垂直排列的文本视图构成。最上面的文本是标题,最下面的是描述,但是描述是隐藏的(View.GONE)。使用ListActivities onListItemClick方法,我可以设置按下行的高度和可见性 @Override protected void onListItemClick(ListView list, View view, int position, long id) {
@Override
protected void onListItemClick(ListView list, View view, int position, long id) {
super.onListItemClick(list, view, position, id);
view.getLayoutParams().height = 200;
view.requestLayout();
TextView desc = (TextView) view.findViewById(R.id.description);
desc.setVisibility(View.VISIBLE);
}
注意:代码被剥离到最基本的部分
上面的代码工作正常,只是它扩展了按下的行以及上面或下面的第10行(下一个卸载视图?)。抛出列表时,行扩展也将更改位置
背景:
listview数据通过托管游标从SQLite数据库检索,并由自定义游标适配器设置。托管光标按复选框值排序
private void updateList() {
todoCursor = managedQuery(TaskContentProvider.CONTENT_URI, projection, null, null, TaskSQLDatabase.COL_DONE + " ASC");
startManagingCursor(todoCursor);
adapter = new TaskListAdapter(this, todoCursor);
taskList.setAdapter(adapter);
}
游标适配器由基本newView()和bindView()组成
问题:
我需要一些跟踪哪些行被扩展的系统。我曾尝试将游标id存储在数组中,然后在适配器中检查行是否应该展开,但我似乎无法让它工作。任何建议都将不胜感激 当您上下滚动时,
列表视图将循环视图,当它需要显示新的子视图时,它将首先查看它是否还没有(如果找到一个,它将使用它)。如果您像您那样(在onListItemClick()
方法中)修改ListView
的子视图,然后滚动列表,那么ListView
最终将重用您修改的子视图View
,并且最终会在您不想要的位置上显示某些视图(如果继续滚动列表视图
,您将看到由于视图
循环而导致的随机位置变化)
防止这种情况发生的一种方法是记住用户单击的位置,然后在适配器中更改该特定行的布局,但只更改所需的位置。您可以将这些ID
存储在HashMap
中(类中的字段):
然后在适配器中,使用状态容器和所有ID
正确设置行,并防止循环使用弄乱我们的行:
private class CustomAdapter extends CursorAdapter {
private LayoutInflater mInflater;
public CustomAdapter(Context context, Cursor c) {
super(context, c);
mInflater = LayoutInflater.from(context);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.title);
title.setText(cursor.getString(cursor.getColumnIndex("name")));
TextView description = (TextView) view
.findViewById(R.id.description);
description.setText(cursor.getString(cursor
.getColumnIndex("description")));
// get the id for this row from the cursor
long rowId = cursor.getLong(cursor.getColumnIndex("_id"));
// if we don't have this rowId in the status container then we explicitly
// hide the TextView and setup the row to the default
if (status.get(rowId) == null) {
description.setVisibility(View.GONE);
// this is required because you could have a recycled row that has its
// height set to 200 and the description TextView visible
view.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.MATCH_PARENT));
} else {
// if we have the id in the status container then the row was clicked and
// we setup the row with the TextView visible and the height we want
description.setVisibility(View.VISIBLE);
view.getLayoutParams().height = 200;
view.requestLayout();
// this part is required because you did show the row in the onListItemClick
// but it will be lost if you scroll the list and then come back
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mInflater.inflate(R.layout.adapters_showingviews, null);
return v;
}
}
如果您想切换所单击的行(有东西告诉我您需要这样做),请在单击时显示TextView
,在另一行单击时隐藏TextView
,然后简单地向onListItemClick()添加else子句
方法并从状态容器中删除单击的行id
,然后还原该行:
//...
else {
status.remove(id);
v.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.MATCH_PARENT));
TextView d = (TextView) v.findViewById(R.id.description);
d.setVisibility(View.GONE);
}
你对我的问题的回答非常正确!我之前曾尝试过一种与ArrayList非常相似的方法,但失败了。我不熟悉HasMaps,但它们很棒。有点不清楚HashMap应该放在哪里,所以我把它作为公共静态放在适配器中,因为所有的读取。我的项目截止日期是4/5。你是一个救生员。我的深度st感恩。@Swiftwork将HashMap
放在你想要的地方,只要确保它可以从你的活动
和适配器
访问就可以了。你可以用数组列表
来操作它,只是它比get()更难操作HashMap上的
方法
您必须在整个列表中循环,以查看id是否已经存在,记住列表中的位置等。。。
private class CustomAdapter extends CursorAdapter {
private LayoutInflater mInflater;
public CustomAdapter(Context context, Cursor c) {
super(context, c);
mInflater = LayoutInflater.from(context);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView title = (TextView) view.findViewById(R.id.title);
title.setText(cursor.getString(cursor.getColumnIndex("name")));
TextView description = (TextView) view
.findViewById(R.id.description);
description.setText(cursor.getString(cursor
.getColumnIndex("description")));
// get the id for this row from the cursor
long rowId = cursor.getLong(cursor.getColumnIndex("_id"));
// if we don't have this rowId in the status container then we explicitly
// hide the TextView and setup the row to the default
if (status.get(rowId) == null) {
description.setVisibility(View.GONE);
// this is required because you could have a recycled row that has its
// height set to 200 and the description TextView visible
view.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.MATCH_PARENT));
} else {
// if we have the id in the status container then the row was clicked and
// we setup the row with the TextView visible and the height we want
description.setVisibility(View.VISIBLE);
view.getLayoutParams().height = 200;
view.requestLayout();
// this part is required because you did show the row in the onListItemClick
// but it will be lost if you scroll the list and then come back
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mInflater.inflate(R.layout.adapters_showingviews, null);
return v;
}
}
//...
else {
status.remove(id);
v.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
AbsListView.LayoutParams.MATCH_PARENT));
TextView d = (TextView) v.findViewById(R.id.description);
d.setVisibility(View.GONE);
}