Android onlistclick切换listview行高导致多重更改

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) {

情况:

我的应用程序包含一个ToDo列表样式的listview(每行有一个复选框)。listview行由两个垂直排列的文本视图构成。最上面的文本是标题,最下面的是描述,但是描述是隐藏的(View.GONE)。使用ListActivities onListItemClick方法,我可以设置按下行的高度和可见性

@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);
        }