1

我用一个CursorAdapter来处理我的ListActivity获取选择查看从ListView控件

public class Mclass extends ListActivity{ 
... 
TheAdapter mAdapter; 
public static HashMap<Long, Boolean> shown = new HashMap<Long, Boolean>(); 
... 

@Override 
protected void onListItemClick(ListView l, View v, int position, long id) { 
    super.onListItemClick(l, v, position, id); 
     Boolean tmp = shown.get(id); 
     if (tmp == null) { // if null we don't have this key in the hashmap so we added with the value true 
      shown.put(id, true); 
     } else { 
      shown.put(id, !tmp.booleanValue()); // if the value exists in the map then inverse it's value 
     } 
    mAdapter.notifyDataSetChanged(); 
     } 

} 

和延伸CursorAdapter和覆盖bindView我的适配器类:

@Override 
public void bindView(View view, Context context, Cursor cursor) { 
    String listText= cursor 
      .getString(cursor 
        .getColumnIndexOrThrow(DataHandler.MY_TEXT)); 

long id = cursor.getLong(cursor.getColumnIndexOrThrow(DataHandler.ROW_ID)); 
    if (Mclass.shown.get(id) != null) { 
     TextView m_text = (TextView) view 
       .findViewById(R.id.my_text); 
     if (m_text != null) { 
      m_text.setVisibility(Mclass.shown.get(id)? View.VISIBLE: 
        View.GONE); 

      if (m_text.isShown()) 
       m_text.setText("STRING"); 
    } 
} 

我的列表项布局定义在xml文件中list_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="wrap_content" 
android:background="#DDDDDD" 
android:orientation="horizontal" > 

<LinearLayout 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:orientation="vertical" > 

    <ImageView 
     android:id="@+id/my_image" 
     android:layout_width="wrap_content" 
     android:layout_height="0dip" 
     android:layout_weight="1" 
     android:paddingRight="1dip" 
     android:paddingTop="1dip" 
</LinearLayout> 

/* 
*I want to toggle this text view's visibility 
*/ 
<TextView 
    android:id="@+id/my_text" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:visibility="gone"//VISIBILITY defined here 
    android:paddingBottom="2dip" 
    android:paddingLeft="4dip" 
    android:paddingRight="4dip" 
    android:paddingTop="5dip" /> 
</LinearLayout> 

如何在onListItemClick内切换TextView在我的布局中的可见性? 我已经试过:

TextView mTextView = (TextView) v.findViewById(R.id.my_text); 
mTextView.setVisibility(mTextView.isShown()? View.GONE: View.VISIBLE); 
mAdapter.notifyDataSetChanged(); 

,但它似乎是选择以随意切换该列表中的项目,不管是一个我点击的。

回答

3

您必须存储您将要隐藏的行的ID。你可以做一个领域的活动来存储这些ID:

HashMap<Long, Boolean> positionHide = new HashMap<Long, Boolean>(); 

其中关键是行和Boolean对象的长期id表示TextView的状态(假就消失了,真的,那是可见)。在onListItemClick()点击的行的ID添加到该字段:

@Override 
    protected void onListItemClick(ListView l, View v, int position, long id) { 
     Boolean tmp = positionHide.get(id); 
     if (tmp == null) { // if null we don't have this key in the hashmap so we added with the value true 
      status.put(id, true); 
     } else { 
      status.put(id, !tmp.booleanValue()); // if the value exists in the map then inverse it's value 
     } 
     mAdapter.notifyDataSetChanged(); 
    } 

还修改bindView()方法:

@Override 
public void bindView(View view, Context context, Cursor cursor) { 
    String listText = cursor.getString(cursor 
      .getColumnIndexOrThrow(DataHandler.MY_TEXT)); 
    long pos = cursor.getLong(cursor.getColumnIndex(DataHandler.ID)); // DataHandler.ID will point to the column _id 
TextView m_text = (TextView) view.findViewById(R.id.my_text); 

    if(status.get(pos) == null) { 
//id is not yet in the hashmap so the value is 
//by default false, the TextView is invisible 
    m_text.setVisibility(View.GONE); 

    } else { 
     // we have the value in the 
     // Hashmap so see what it is and set the 
    // textview visibility from this value 

     if (tmp.booleanValue()) { 
      m_text.setVisibility(View.VISIBLE); 
      } else { 
       m_text.setVisibility(View.GONE); 
        } 
      } 
    if (m_text != null) 
    m_text.setText(listText); 

} 

对于这个工作,你就必须在你的数据库中的列_id INTEGER PRIMARY KEY AUTOINCREMENT (也添加到查询中)。

+0

太棒了!我明白你要去哪里。但为了切换,我不会删除并添加我的id从'ArrayList positionHide'然后在'bindView'中做另一个检查? – ababzy 2012-03-03 20:15:17

+0

@ababzy对不起,当我第一次看到你的问题,我只看到“隐藏'TextView'”。看到我更新的答案。 – Luksprog 2012-03-03 20:44:07

+0

@ababzy我忘了,你必须在'listItemClick()'上调用'mAdapter.notifyDataSetChanged()'来通知'ListView'有更新的东西。 – Luksprog 2012-03-03 21:22:47

1

你问题是视图在列表视图中被重用。即使你有一个由100个项目组成的列表,也只有10个左右的视图实例(取决于屏幕上可以安装多少)。如果您可以看到bindView方法将视图重用为参数。

你已经做了什么,是一个视图,显示例如列表中的第23项,并隐藏文本框。当第23项滚动出屏幕时,它的视图被重用,但只有值被第33项的数据取代,您为重复使用的视图设置的可见性和其他参数保持不变。

你应该做的是给所有列表项添加一个状态布尔值,并在适配器的bindView中根据项目当前所需的状态切换文本框的可见性。

另一个重要的事情是,当你点击该项目时,不会调用bindView方法。因此,您还应该切换onClick方法中的可见性,以使更改具有实例性。如果你错过了这个视图,只有当这个项目被滚动出来并再次滚动时,这个视图才会改变 - 这就是bindView检查可见性布尔值时的情况。

将数据集观察者通知DataSet中的更改并让ListView调用所有可见项的bindView会更加优雅,但它也更耗费资源。

HashMap<Long, Boolean> positionHide = new HashMap<Long, Boolean>(); 
    @Override 
    protected void onListItemClick(ListView l, View v, int position, long id) { 
     Boolean tmp = positionHide.get(id); 
     if (tmp == null) { // if null we don't have this key in the hashmap so we added with the value true 
      positionHide.put(id, true); 
      tmp = true; 
     } else { 
         tmp = !tmp.booleanValue(); 
      positionHide.put(id, !tmp.booleanValue()); // if the value exists in the map then inverse it's value 
     } 
     // You should also hide the text view, because bindView will not be called until the list item is scrolled out and in again 
       TextView m_text = (TextView) view.findViewById(R.id.my_text); 
     if (m_text != null) { 
       if(tmp) { 
          // We should hide the text view 
          m_text.setVisibility(View.GONE); 
        } else { 
         // We should display the text view 
          m_text.setVisibility(View.VISIBLE); 
        } 
     } 
    } 


@Override 
public void bindView(View view, Context context, Cursor cursor) { 
    String listText = cursor.getString(cursor 
      .getColumnIndexOrThrow(DataHandler.MY_TEXT)); 
      TextView m_text = (TextView) view.findViewById(R.id.my_text); 
    if (m_text != null) { 
      m_text.setText(listText); 
      long pos = cursor.getLong(cursor.getColumnIndex(DataHandler.ID)); // DataHandler.ID will point to the column _id 
      if((positionHide.get(pos) != null)&&(positionHide.get(pos))) { 
         // We should hide the text view 
         m_text.setVisibility(View.GONE); 
       } else { 
        // We should display the text view 
         m_text.setVisibility(View.VISIBLE); 
       } 
      } 
} 

对于这个工作,你需要在数据库中有列_id INTEGER PRIMARY KEY AUTOINCREMENT(也添加到查询)。

+0

我明白了!这解释了为什么我选择一个项目时似乎为随机项目设置了可见性状态。我意识到'getView'可以工作,但它也会挫败使用'CursorAdapter'的目的。 – ababzy 2012-03-03 20:48:02

+0

你是对的,不要使用自定义数组类型的适配器,使用CursorAdapter,并依靠slukian的答案,它基本上是同样的事情,但有一个游标和bindView方法。正如他写的,代替数组,使用哈希映射关联“显示文本视图”状态到当前项目的ID,并检查每个新项目的哈希映射。我会为你编辑代码。 – 2012-03-04 08:08:23

+0

编辑是在同行审查,我编辑的代码添加到我的答案。重要的是在点击时改变可见性,因为您在HashMap中设置的标志只会在您的项目滚出后才会生效,并且会再次滚动 - 即调用绑定视图时。 另一种解决方案是在单击项目时通知数据集侦听器有关更改。这是一个更清洁的MWC设计,但使用听众隐藏项目是更经济的形式编码,并从处理的角度来看(当数据集监听器通知,bindView将被称为4all项目。) – 2012-03-04 08:18:37

1

那么你不应该使用ListView任何活动的视图,请尝试使用TableLayout或LinearLayout来代替。 看看this blog帖子了解更多细节,但它是用于CheckBoxes的,但对任何活动视图都适用。

+0

不正确,因为方式listview优化大量项目的视图,并不总是建议使用表格或线性布局大量项目 – the100rabh 2012-03-03 14:47:15

+0

@ the100rabh完全一样,我已经在博客文章中添加了警告。但是,如果行数较少,则性能下降不会很明显。 – noob 2012-03-03 14:52:30