Android selector item android:state_hovered 鼠标悬停样式

2次阅读

android:state_hovered在多数android移动设备上不生效,仅限外接鼠标或模拟悬停的chromebook/模拟器;应优先使用onhoverlistener并注意资源混淆保留。

Android selector item android:state_hovered 鼠标悬停样式

Android selectorandroid:state_hovered 根本不生效?

绝大多数情况下,android:state_hovered 在真机上完全没反应——不是你写错了,是 Android 系统压根不给它机会。从 Android 4.0 到 14,只有极少数带真正触摸板或外接鼠标且开启“模拟悬停”的设备(比如部分 Chromebook 或调试中的模拟器)会触发该状态。普通手机、平板连触摸事件都走 state_pressed,根本不会进 state_hovered 分支。

实操建议:

  • 别在面向移动设备的 ui 中依赖 android:state_hovered 做核心交互反馈
  • 如果必须支持鼠标悬停(比如折叠屏/大屏模式),先用 Configuration.uiMode 判断是否处于 UI_MODE_TYPE_DESKUI_MODE_TYPE_CAR
  • View.setOnHoverListener() 手动监听 MOTION_Event_ACTION_HOVER_ENTER/EXIT,比靠 selector 可靠得多

为什么 selector 里写了 state_hovered 却总匹配到 state_focused

因为 Android 的状态匹配是「按顺序找第一个全匹配项」,而 state_focusedstate_hovered 在多数输入场景下会同时为 true(比如鼠标移入一个可聚焦的 Button)。如果你把 state_focused 的 item 写在 state_hovered 前面,系统就永远选不到后者。

实操建议:

  • 把最具体的组合放前面:比如 <item android:state_hovered="true" android:state_focused="false"></item> 要比单独 state_hovered 更准
  • 避免混用 state_focusedstate_hovered 在同一 selector 中,除非你明确控制焦点获取逻辑
  • adb shell dumpsys input_method 或布局检查器确认当前 View 的实际状态值

替代方案:用 View.OnHoverListener 实现可靠悬停反馈

比起赌系统会不会发 state_hovered,直接监听更可控。它不依赖主题、不被 selector 顺序干扰,还能做渐变、延迟显示等原生 selector 做不了的事。

实操建议:

  • onCreate()onViewCreated() 中注册:view.setOnHoverListener((v, event) -> { ... })
  • 只响应 event.getAction() == MotionEvent.ACTION_HOVER_ENTERACTION_HOVER_EXIT,忽略 ACTION_HOVER_MOVE(太频繁)
  • 配合 ValueAnimator 做颜色过渡,比 selector 切换更顺滑;注意在 ACTION_HOVER_EXIT 时取消动画防止内存泄漏
  • 记得在 onDestroy()onViewDetachedFromWindow() 中设为 NULL,避免隐式引用

混淆和构建时 state_hovered 属性被删掉?

AGP 8.0+ 默认启用资源压缩(shrinkResources true),而 android:state_hovered 是较冷门属性,R8 可能误判为未使用并移除对应资源 ID,导致运行时报 ResourceNotFoundException 或静默失效。

实操建议:

  • res/raw/keep.xml 中显式保留:<resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@drawable/*,@color/*"></resources>
  • 或者在 proguard-rules.pro 加一行:-keep class android.R$attr { public Static int state_hovered; }
  • 验证方式:反编译 APK,搜 state_hovered 是否还在 resources.arsc

真正麻烦的不是怎么写对这个属性,而是得时刻记住:它只在特定硬件 + 特定系统配置 + 特定 UI 模式下才可能起作用。其他时候,它就是个安静的摆设。

text=ZqhQzanResources