ListView 保持选中状态?

发布于 2024-09-07 14:27:08 字数 83 浏览 6 评论 0原文

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

I have a list view full of items, after the users selects an item it lights up, and then it goes back to normal. Is there a way to make it so that when the user selects an item in my ListView it stays selected, and highlighted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

反话 2024-09-14 14:27:08

显然,“消失的选择”是有意设计的。这就是所谓的“触摸模式”。我通读了该文件,但仍然不知道为什么他们认为这是一个好主意。我的猜测是,由于 Android 最初是为小屏幕设备设计的,因此他们希望您用一个列表填充屏幕,然后当用户单击某个项目时,移动到另一个屏幕上的新列表。因此,用户不会意识到 Android 丢失了所选项目的跟踪。

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

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

1. 在 XML 布局文件中,

转到 ListView 元素和以下属性:android:choiceMode="singleChoice"。我不完全确定它的作用(它本身不允许用户选择任何内容),但如果没有此属性,下面的代码将无法工作。

2. 定义以下类

它用于跟踪所选项目,并且还允许您模拟 Java 中的引用传递:

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

3. 将以下代码放在某处

我假设您将其放在 Activity 中,但是它实际上可以放在任何类中:

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)附加到 ListView,并覆盖 ArrayAdapter.getView() code> 包含一些更改所选项目背景的代码。

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 中的“内部选择”与“键盘选择”或任何名称保持同步,请发表评论。它叫什么

Apparently the "disappearing selection" is by design; it's something called "touch mode". I read through that document and still I have no idea why they thought it was a good idea. My guess is that, since Android was originally designed for small-screen devices, they expected that you would fill the screen with a list and then, when the user clicks an item, move to a new list on a different screen. Thus, the user wouldn't be aware that Android lost track of the selected item.

But this behavior is quite annoying if, for example, you want the user to select an item and then show information about that item on the same screen. If the selection disappears, how is the user supposed to know what they clicked (assuming of course that users have the attention span of a goldfish)?

One possible solution is to change all the list items into radio buttons. I don't really like that solution because it wastes screen real estate. I'd rather just use the background color to show which item is selected. I have seen one solution so far but it is not quite complete or general. So here's my solution:

1. In your XML layout file

Go to your ListView element and the following attribute: android:choiceMode="singleChoice". I'm not entirely sure what this does (by itself, it doesn't allow the user to select anything) but without this attribute, the code below doesn't work.

2. Define the following class

It is used to keep track of the selected item, and also allows you to simulate pass-by-reference in Java:

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

3. Put the following code somewhere

I'll assume you put it in your Activity, but it could go in any class really:

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

This code does two things: it attaches your list items (e.g. List<String>) to your ListView, and it overrides ArrayAdapter.getView() with some code that changes the background of the selected item.

4. Use that code to set up your list

For example:

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

That's all! The above assumes you want single selection. With some small modifications to getView(), you could support multi-selection too, I guess, but you should probably use checkboxes instead.

Warning: this solution needs further development. If the user uses arrow keys or buttons to select an item, that item will not be selected from the IntHolder's perspective. If the user presses the unlabeled button (what's the name of that button? "Enter"?) then the item will become "officially" selected but then you have another problem because if the user uses the arrow keys again, it will sort of look like two items are selected. Leave a comment if you figure out how to keep the "internal selection" in the IntHolder synchronized with the "keyboard selection" or whatever it's called. What is it called, anyway?

清秋悲枫 2024-09-14 14:27:08

ListView中有一个属性叫做listSelector:

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

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


编辑 Stan之后comment

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

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

② 使用适配器,该适配器使用实现 Checkable< 的视图/a> 界面,如 CheckedTextViewsimple_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);
    }
}

There is an attribute in ListView called listSelector:

Drawable used to indicate the currently selected item in the list.

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


EDIT after Stan comment

To ensure that a ListView stays selected, you should

① Set the view's attribute choiceMode via xml or programmatically.

② Use an adapter that uses views which implement Checkable interface, like CheckedTextView (inside simple_list_item_single_choice layout).

File 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);
    }
}
叶落知秋 2024-09-14 14:27:08

这里有一个比 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:
仅使用 OnTouchListener 从 ListView 获取项目

Here a simpler solution than Qwertie's:

Do not rely on given selection mechanism. Do it yourself.

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

Also this method only deals with clicks and will not work if the user uses the arrow keys.

Disclaimer: De-highlighting after touch does not work reliably.

Credits for the touching part go to ozik.dev:
Get Item from ListView only with OnTouchListener

女皇必胜 2024-09-14 14:27:08

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

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

just add this to your listview layout

 android:listSelector="@drawable/selector_expandable_listview" 
 android:drawSelectorOnTop="true"
辞慾 2024-09-14 14:27:08

使用 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);
        }
    });

Use a Selector.XML File and this code:

    //SetOnClickListner to catch Events
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         view.setSelected(true);
        }
    });
烟雨凡馨 2024-09-14 14:27:08

只需将其添加到您的 ListView 中:

android:listSelector="@color/my_color"

Just add this to your ListView:

android:listSelector="@color/my_color"
心碎的声音 2024-09-14 14:27:08

这个答案有效,试试这个

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

This answer is working try this one

@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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文