ListView 保持选中状态?

Posted

技术标签:

【中文标题】ListView 保持选中状态?【英文标题】:ListView stay selected? 【发布时间】:2011-03-07 21:11:53 【问题描述】:

我有一个充满项目的列表视图,用户选择一个项目后它会亮起,然后又恢复正常。有没有办法让它在用户在我的 ListView 中选择一个项目时保持选中状态并突出显示?

【问题讨论】:

这是一篇有用的文章:***.com/questions/5925892/… 【参考方案1】:

只需将其添加到您的 ListView:

android:listSelector="@color/my_color"

【讨论】:

【参考方案2】:

使用 Selector.XML 文件和此代码:

    //SetOnClickListner to catch Events
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
         view.setSelected(true);
        
    );

【讨论】:

【参考方案3】:

只需将其添加到您的列表视图布局中

 android:listSelector="@drawable/selector_expandable_listview" 
 android:drawSelectorOnTop="true"

【讨论】:

【参考方案4】:

这里有一个比 Qwertie 更简单的解决方案:

不要依赖给定的选择机制。自己动手。

View mSelectedItemView = null; //class member variable
View mTouchedItemView = null; //class member variable

ListView v = (ListView) getActivity().findViewById(R.id.listView);
// select on click
v.setOnItemClickListener(new OnItemClickListener() 
    @Override
    public void onItemClick(AdapterView<?> adapter,
            View clickedViewItem, int position, long id) 
        if (mSelectedItemView != null)
            selectedItemView.setBackgroundColor(Color.WHITE);
        clickedViewItem.setBackgroundColor(Color.YELLOW);
        mSelectedItemView = clickedViewItem;
    
);
// highlight on touch
v.setOnTouchListener(new OnTouchListener() 
    @Override
    public boolean onTouch(View v, MotionEvent event) 
        if (v instanceof ListView) 
            ListView listView = (ListView) v;
            // Find the child view that was touched (perform a
            // hit test)
            Rect rect = new Rect();
            int childCount = listView.getChildCount();
            int[] listViewCoords = new int[2];
            v.getLocationOnScreen(listViewCoords);
            int x = (int) event.getRawX() - listViewCoords[0];
            int y = (int) event.getRawY() - listViewCoords[1];
            View child;
            for (int i = 0; i < childCount; i++) 
                child = listView.getChildAt(i);
                child.getHitRect(rect);
                if (rect.contains(x, y)) 
                    View touchedView = child;
                    if (event.getAction() == MotionEvent.ACTION_DOWN) 
                        touchedView
                                .setBackgroundColor(Color.RED);
                        mTouchedItemView = touchedView;
                     else if (event.getAction() == MotionEvent.ACTION_UP) 
                        mTouchedItemView 
                                .setBackgroundColor(Color.WHITE);
                    
                
            
        
        return false;
    
);

此外,此方法仅处理点击,如果用户使用箭头键则不起作用。

免责声明:触摸后取消突出显示无法可靠地工作。

感人部分归功于 ozik.dev: Get Item from ListView only with OnTouchListener

【讨论】:

是的,你的权利 Jack Miller :) 所以它完美运行【参考方案5】:

ListView中有一个属性叫listSelector:

Drawable 用于指示列表中当前选中的项目。

http://developer.android.com/reference/android/widget/AbsListView.html#attr_android:listSelector


编辑 Stan 评论后

为确保ListView 保持选中状态,您应该

①通过xml或编程方式设置视图的属性choiceMode

②使用一个使用实现Checkable接口的视图的适配器,例如CheckedTextView(在simple_list_item_single_choice布局内)。

文件TestActivity.java

public class TestActivity extends Activity 

    private static final int SINGLE_CHOICE = android.R.layout.simple_list_item_single_choice;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);

        String[] items = "test 1", "test 2", "test 3";
        ListAdapter adapter = new ArrayAdapter<String>(this, SINGLE_CHOICE, items);
        ListView list = (ListView) findViewById(R.id.testList);
        list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        list.setAdapter(adapter);
    

【讨论】:

这无济于事,因为 ListView 是这样工作的。使用选择器 ListView 只会在单元格被触摸时显示突出显示的单元格,但在用户结束触摸后,单元格将变为未选中/未聚焦等,因此无法仅使用选择器显示它已被选中。 @Stan 你是对的;我也编辑了帖子以使用适配器。【参考方案6】:

这个答案很有效,试试这个

@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long arg3)
    
        for(int a = 0; a < parent.getChildCount(); a++)
        
            parent.getChildAt(a).setBackgroundColor(Color.TRANSPARENT);
        
    view.setBackgroundColor(Color.GREEN);

【讨论】:

现在假设您的列表中有 1000 个项目,因此每次用户点击您的循环都会触发。这个解决方案是完全不够的,还会导致大列表冻结/挂起,还会导致不可预知的视觉错误。 列表视图重用了它的子视图,所以它只会被屏幕上适合的项目调用,这很好。【参考方案7】:

显然,“消失的选择”是设计使然;它叫做“touch mode”。我通读了那份文件,但我仍然不知道他们为什么认为这是个好主意。我的猜测是,由于 Android 最初是为小屏幕设备设计的,他们希望你会用一个列表填满屏幕,然后当用户点击一个项目时,移动到另一个屏幕上的新列表。因此,用户不会意识到 Android 丢失了所选项目的跟踪。

但是,如果您希望用户选择一个项目,然后在同一屏幕上显示有关该项目的信息,那么这种行为会很烦人。如果选择消失了,用户应该如何知道他们点击了什么(当然假设用户有金鱼的注意力)?

一种可能的解决方案是将所有列表项更改为单选按钮。我不太喜欢这种解决方案,因为它浪费了屏幕空间。我宁愿只使用背景颜色来显示选择了哪个项目。到目前为止,我已经看到了一种解决方案,但它并不完整或通用。所以这是我的解决方案:

1。在您的 XML 布局文件中

转到您的 ListView 元素和以下属性:android:choiceMode="singleChoice"。我不完全确定这是做什么的(它本身不允许用户选择任何东西)但是没有这个属性,下面的代码就不起作用。

2。定义如下类

它用于跟踪选定的项目,还允许您在 Java 中模拟 pass-by-reference:

public class IntHolder 
    public int value;
    public IntHolder() 
    public IntHolder(int v)  value = v;  

3。将以下代码放在某处

我假设你把它放在你的活动中,但它实际上可以放在任何类中:

static void setListItems(Context context, AdapterView listView, List listItems, final IntHolder selectedPosition)

    setListItems(context, listView, listItems, selectedPosition, 
                 android.R.layout.simple_list_item_1, 
                 android.R.layout.simple_spinner_dropdown_item);

static void setListItems(Context context, AdapterView listView, List listItems, final IntHolder selectedPosition, 
                         int list_item_id, int dropdown_id)

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
        public void onItemClick(AdapterView<?> list, View lv, int position, long id) 
            selectedPosition.value = position;
        
    );
    ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(context, list_item_id, listItems)  
        @Override
        public View getView(int position, View convertView, ViewGroup parent) 
            View itemView = super.getView(position, convertView, parent);
            if (selectedPosition.value == position)
                itemView.setBackgroundColor(0xA0FF8000); // orange
            else
                itemView.setBackgroundColor(Color.TRANSPARENT);
            return itemView;
        
    ;
    adapter.setDropDownViewResource(dropdown_id);
    listView.setAdapter(adapter);

这段代码做了两件事:它将您的列表项(例如List&lt;String&gt;)附加到您的ListView,并使用一些更改所选项目背景的代码覆盖ArrayAdapter.getView()

4。使用该代码设置您的列表

例如:

ListView _list;
IntHolder _selectedItem = new IntHolder(-1); // nothing selected at first

@Override
protected void onCreate(Bundle savedInstanceState) 
    ...
    _list = (ListView)findViewById(R.id.list);
    List<String> items = Arrays.asList("Item 1", "Item 2", "Item 3");
    setListItems(this, _list, items, _selectedItem);

就是这样!以上假设您想要单选。对 getView() 进行一些小的修改,我猜你也可以支持多选,但你可能应该使用复选框。

警告:此解决方案需要进一步开发。如果用户使用箭头键或按钮来选择一个项目,那么从 IntHolder 的角度来看,该项目将不会被选中。如果用户按下未标记的按钮(该按钮的名称是什么?“Enter”?)然后该项目将成为“正式”选择但随后您遇到另一个问题,因为如果用户再次使用箭头键,它会看起来有点就像选择了两个项目。如果您知道如何使 IntHolder 中的“内部选择”与“键盘选择”或其他任何名称保持同步,请发表评论。它到底叫什么

【讨论】:

当一个屏幕同时包含列表(左半部分)和所选行的详细信息(右半部分)时,这对于片段也很有帮助。所以这是告诉/显示用户他以前的选择的唯一方法! 我已经坚持了 6 个小时,我真的需要帮助。 ***.com/questions/35108940/why-cant-i-remove-an-item/…

以上是关于ListView 保持选中状态?的主要内容,如果未能解决你的问题,请参考以下文章

winform。 listview 更新数据后刷新

Listview 选中一直高亮和更新有冲突?

为啥当我在选中 CheckBox 的情况下滚动 ListView 时,它会变为未选中状态?

怎么获取listview 中checkbox的选中状态

vb.net 点击按钮选中listview最后一行

Android入门第28天-ListView嵌套CheckBox在滚动时失去选中状态的问题