点击ListView中的项目后如何使其保持“按下”状态?

22

我有一个ListView,当通过onItemClick监听器点击一行项目时,它会打开另一个活动。

我希望该行在被点击后能保持其按下状态,直到屏幕切换到新活动。我认为这将为用户提供更清晰的体验,而且你可以在大多数按钮(如打开/关闭对话框或切换活动)中看到类似的效果。

我尝试在onItemClick()监听器中使用view.setPressed(true)来设置状态,但它似乎是在按下状态返回正常之后短暂地调用,因此会闪烁。

例如:

mListView.setOnItemClickListener(new OnItemClickListener() {

   @Override
   public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
       view.setPressed(true);
       //start an activity
   }
});

这段代码几乎可以正常工作,除了会有闪烁现象(用户按下列表项,它变为选中状态,然后用户松开手指完成点击,它会在调用setPressed(true)之前的短暂时间内回到正常状态,然后再次变为选中状态)。

有什么建议吗?

谢谢。

编辑:我应该提到,我正在使用一个XML可绘制选择器来定义列表背景的正常,按下,选中等状态。


只需拦截您的视图的触摸事件并从那里调用setPressed即可。 - Eugene Pankov
7个回答

27

我曾经遇到过完全相同的问题,非常令人沮丧!

不过,这个问题很容易解决:用state_selected替换state_pressed。在调用onItemClick()方法之前,按下状态仍然会快速变化,但由于您的主题不依赖于state_pressed,因此闪烁不会可见。一旦在onItemClick()方法中设置了state_selected,该项将保持选中状态,而不会出现任何闪烁。

以下是我的选择器:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Selected Item -->
    <item android:state_selected="true"
        android:drawable="@color/list_pressed" />

    <!-- Default Item -->
    <item android:state_selected="false"
        android:drawable="@android:color/list_default" />
</selector>

我的 onListItemClick(...) 方法:

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    v.setSelected(true);
    //TODO: add further actions here
}

我终于有时间测试了一下,它确实可以工作!感谢你几个月后分享你的答案。 - cottonBallPaws
1
@RudolfMeijering 我遇到了一个问题。当我们从列表视图中选择第二个项目时,它会显示我选择了两个项目,但对于第一个项目它可以正常工作。 - Rohit
滚动一个大列表会导致每个视图被重用于不同的行。当您将 setSelected 调用的视图滚动到屏幕外时,它将无法与列表中选定的项目保持同步。 - Jared Kells
你不需要使用 state_selected="false" - 只要前一个项目使用相同的键设置为 true 即可。 - AlikElzin-kilaka
1
我们甚至有onListItemClick回调函数吗?! - Behnam
显示剩余7条评论

6
在Android 3.0之前,您可以使用自定义视图中的自定义状态或从适配器更改视图的背景颜色来完成此操作。从Android 3.0开始,您可以使用新的state_activated来保留所选列表项。

1
这个目标包括3.0以下的设备,所以我将不得不选择其中一个旧有路线。在这两种方法中,是否有一种内置的方法可以使用,当需要更改背景颜色时会被触发?(在确定它是实际点击之后,在返回背景到未按下状态之前)。还是说我必须亲自动手用onTouch方法,这似乎有点可怕,关于保持ListView正常运作。谢谢 - cottonBallPaws

3

在适配器内部,您可以引用要更改状态的视图。假设您有一个带有标题和星形(即喜爱的星形)的ListView,并且希望在触摸时保持“选定/按下”状态。请覆盖getView并执行以下操作:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final View view = super.getView(position, convertView, parent);
    final ImageButton favorite = (ImageButton) view.findViewById(R.id.favorite);
    favorite.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "Star pressed...");
            v.setSelected(!v.isSelected());
        }
    });
    return view;
}

您的ImageButton布局应该引用类似这样的可绘制对象:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@android:drawable/star_big_on" />
    <item android:state_pressed="true" android:drawable="@android:drawable/star_big_on" />
    <item android:drawable="@android:drawable/star_big_off" />
</selector>

2
你正在使用 XML 进行选择器。请检查你是否正确设置了状态。
当你调用 view.setPressed(true) 方法时,它将使用为 android:state_pressed="true" 状态设置的可绘制对象。
<item android:state_pressed="true"   
    android:drawable="@color/gray" />

状态正常,问题在于找到一种方法使其在成功“按下”后保持按下状态(或至少看起来像按下状态)。 - cottonBallPaws
抱歉,之前有误,现已更正,请查看我的编辑,确保你在xml中只将state_pressed="true"用于事件。 - Labeeb Panampullan

0

你是否已经尝试过将unscheduleDrawabledrawableStateChanged结合使用?

这样,你可以监听状态变化,然后立即取消调度并将其设置回按下状态。

也许就不会再出现闪烁了。


这似乎可能会有所帮助,但我不确定何时调用它,因为按下并不总是意味着已经“点击”,因为它可能会变成长按或取消按下。 - cottonBallPaws
嗯,没错。只有当长按已经完成时,你才会知道它是一个长按。然后你需要监听长按事件并再次设置背景。 - anon
只是另一种选择...如果您使用类似动画或其他平滑过渡方式,那么它至少不会闪烁,而是“平滑地”混合,这样怎么样? - anon
@littleFluffyKitty,只是提醒一下您 ;) - anon

0

这会在按钮的onClick事件中更改列表行的背景。不过,我正试图使用列表行本身的onClick来完成这个任务。这仍然存在同样的问题,它使用了onClick触发,在按压状态已经恢复正常后才被触发。 - cottonBallPaws

0

不要使用选择器XML,而是手动更改列表项图像。这样您就可以控制特定图像的持续时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接