奇怪的列表视图项目选择器外观(手指离开屏幕时未移除按下状态)

Posted

技术标签:

【中文标题】奇怪的列表视图项目选择器外观(手指离开屏幕时未移除按下状态)【英文标题】:Wierd listview item selector appearance (pressed state was not removed when finger left the screen) 【发布时间】:2012-05-02 01:19:28 【问题描述】:

我有如下列表视图项

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="horizontal"
    android:descendantFocusability="blocksDescendants"
    >

    <TextView
        android:id="@+id/textView1"
        android:layout_
        android:layout_
        />

    <CheckBox
        android:id="@+id/checkBox1"
        android:layout_
        android:layout_
        android:background="@drawable/music_list_item_checkbox_bg"
        />
</LinearLayout>

music_list_item_checkbox_bg.xml 是一个选择器,它会根据不同的状态显示不同的drawable。

<selector xmlns:android="http://schemas.android.com/apk/res/android" >

    <item 
          android:state_pressed="false"
          android:state_selected="true"
          android:drawable="@drawable/btn_checkbox_check_untapped" />

    <item android:state_selected="true" 
          android:state_pressed="true"
          android:drawable="@drawable/btn_checkbox_check_tapped" />

    <item android:state_selected="false"  
          android:state_pressed="false"
          android:drawable="@drawable/btn_checkbox_uncheck_untapped" />

    <item android:state_selected="false"  
          android:state_pressed="true"
          android:drawable="@drawable/btn_checkbox_uncheck_tapped" />

</selector>

当我按下列表视图中的项目并将触摸屏留在项目内时,取决于不同状态的可绘制对象是正确的。

问题: 但是如果我按下项目并将手指水平移出项目(触摸点的 X 位于项目的顶部和底部之间) ,然后离开屏幕,复选框的drawable将保持按下状态。 (如果触摸点的X不在项目的顶部和底部,则状态正确)。

我尝试在复选框中添加android:duplicateParentState="true" 以获得与父级相同的状态,但它不起作用。

我很困惑,有人有什么想法吗?

已编辑

我之前尝试在项目中实现 onTouch 和 onIntercept,但如果我返回 super.onTouch(MotionEvent 事件),则只能接收动作。只返回true,则接收到sequence event,但是listview的onItemClick不起作用。 我尝试阅读 AbsListview 中的 onTouch 代码 sn-p 以找出解决问题的方法,我发现有时 child(item) 的按下状态不会通过调用 child.setPressed(false) 来清除为 false,这取决于不同的触摸模式。

我真的很想要一个解决方案!!!

【问题讨论】:

这是一个纯粹的猜测,但也许是因为该动作在视图(按下)上注册了一个 Down 事件,但没有为 that 视图注册一个相应的 Up 事件? 【参考方案1】:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" 
         android:drawable="@drawable/btn_checkbox_check_tapped" />
    <item android:state_selected="true" 
         android:drawable="@drawable/btn_checkbox_check_tapped" />
        <item android:drawable="@drawable/btn_checkbox_uncheck_untapped" />
</selector>

尝试使用这些选择器作为背景

【讨论】:

如果上述方法在实现 ontouch 并识别 action up 事件并使用 adapter.notifyDataSetChanged() 刷新列表视图后不起作用 我解决了这个问题,但可能不是一个好的解决方案或官方解决方案。【参考方案2】:

尝试让其中的视图无法聚焦...

<TextView
    android:id="@+id/textView1"
    android:layout_
    android:layout_
    />

<CheckBox
    android:id="@+id/checkBox1"
    android:layout_
    android:layout_
    android:background="@drawable/music_list_item_checkbox_bg"
android:focussableInTouchMode="false"
android:focussable="false"
    />

您不能在触摸模式下使列表项成为焦点...这里因为您的复选框是可聚焦的,它会产生问题...

【讨论】:

我试过了,还是不行。我使用 android:descendantFocusability="blocksDescendants" 来避免项目获得焦点。 @dreamtale .. 尝试删除 i认为它甚至不需要,因为 ListView 项目不能保持选中状态.. 我删除并尝试了与您发布的相同的代码,它仍然无法正常工作。这个问题真的让我很沮丧。我问了一位工程师,他发现他的 gridview 也有同样的问题。可能listview或者gridview想要和你之前写的效果一样有同样的问题。【参考方案3】:

我解决了问题,但可能不是一个好的解决方案或官方解决方案。

我使用自己的MyListView 类从ListView 扩展而不是SDK ListView 并在其onTouchEvent 中接收ACTION_UPACTION_CANCEL,然后手动将项目的按下状态设置为false .更多细节请看下面的代码。

@Override
public boolean onTouchEvent(MotionEvent event)

    boolean handled = super.onTouchEvent(event);
    Log.d("test", "event " + event.toString());
    int action = event.getAction();

    switch (action)
    
    case MotionEvent.ACTION_DOWN:
        m_downPosition = pointToPosition((int)event.getX(), (int)event.getY());
        Log.d("test", "The down position " + m_downPosition);
        break;

    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:
        int position = m_downPosition - getFirstVisiblePosition();
        View child = INVALID_POSITION != m_downPosition ? getChildAt(position) : null;
        if (null != child)
        
            child.setPressed(false);
        
        break;

    default:
        break;
    
    return handled;

【讨论】:

【参考方案4】:

您应该尝试使用这样的默认选择器项

<item android:drawable="@drawable/btn_checkbox_uncheck_untapped" />

这将处理所有剩余的状态 或者您应该有一个选择器项来处理您的 xml 中缺少的 focussed 状态。

【讨论】:

我试过了,还是不行,Android lint 也有警告:No android:state_ attribute found on 2, later states not reachable 嗯。我最后有这个,即在所有其他选择器状态之后。我不知道这是否有所作为。你也尝试过 state_focussed 看到警告后,我尝试将它移到最后,但不幸的是它仍然不起作用,这个问题让我发疯。我已经尝试了 2 个小时。 我解决了这个问题,但可能不是一个好的解决方案或官方解决方案。【参考方案5】:

为您的项目扩展 LinearLayout 并覆盖其中的 onTouch。处理 ACTION_CANCEL 事件(返回 true)并更新项目的按下和选择状态。

class ItemLayout extends LinearLayout 

    @override
    boolean onTouch(MotionEvent ev) 
        switch(ev.getAction()) 
            case ACTION_CANCEL: 
                // Update/reset pressed and selected states of item or checbkox
                return true;
        
        return super.onTouch(ev);
    


参考http://groups.google.com/group/android-developers/browse_thread/thread/df75c5b8e4605167#

希望对您有所帮助。

<ItemLayout 
  ....>
    <TextView
       ...
       />

    <CheckBox
       ...
       />
</ItemLayout >

【讨论】:

我的listview项目前是extends LinearLayout,我之前试过实现onTouch和onIntercept,但是只能接收动作down,如果我返回super.onTouch(MotionEvent事件),只返回true,然后是sequence event会收到,但是listview的onItemClick不起作用。 如果返回super,item中只能收到action down。 是否以与我给出的代码相同的方式完成?查看谷歌群组链接,它说当手指离开视线时会发生 ACTION_CANCEL .. 我之前试过,记得Action_cancel没有收到,我稍后再试,如果收到了会通知你。 不,操作取消也无法接收。我差点放弃了,过段时间我会再尝试解决的。

以上是关于奇怪的列表视图项目选择器外观(手指离开屏幕时未移除按下状态)的主要内容,如果未能解决你的问题,请参考以下文章

手指离开手机屏幕后UIView自动向上滑动

05.触屏事

苹果手机。在一个手指触摸屏幕时检测另一个手指触摸

js实现touch移动触屏滑动事件

使用 kivy 和 python 返回屏幕管理器时未设置焦点

无法在列表视图项目中正确选择文本