前言
焦点一般在TV设备,投影仪设备开发中使用很多。因为这些设备不带触控与键鼠输入,而是使用遥控器。本博客讲解与记录焦点开发的一些功能与细节。
在xml里关于焦点的属性
<!-- 控制视图是否可以获取焦点。默认情况下,这是“自动”,它让框架确定用户是否可以将焦点移动到视图。通过将此属性设置为 true,视图可以获取焦点。通过将其设置为“false”,视图将不会获得焦点。 此值不会影响直接调用 {@link android.view.ViewrequestFocus} 的行为,无论此视图如何,它都会始终请求焦点。 它只影响焦点导航尝试移动焦点的位置。 --> <attr name="focusable" format="boolean|enum"> <!-- 控制视图是否可以在触摸模式下获得焦点的布尔值。如果对于一个视图是这样,则该视图可以在单击时获得焦点,并且如果单击另一个未将此属性设置为 true 的视图,则可以保持焦点。 这个开启后是有一个副作用的,点击一个View需要点击二次,第一次点击变成了获取焦点,第二次点击才会执行onClickListener--> <attr name="focusableInTouchMode" format="boolean" /> <!-- 此视图是否为默认焦点视图。每个键盘导航集群只有一个视图可以将此属性设置为 true。 请参阅 {@link android.view.ViewsetFocusedByDefault(boolean)}。 --> <attr name="focusedByDefault" format="boolean" /> <!--此视图在获得焦点但未在其背景中定义 {@link android.R.attrstate_focused} 时是否应使用默认焦点突出显示。 --> <attr name="defaultFocusHighlightEnabled" format="boolean" /> <!-- 屏幕阅读器辅助工具是否应将此视图视为可聚焦单元。 请参阅 {@link android.view.ViewsetScreenReaderFocusable(boolean)}。 默认值 {@code false} 让屏幕阅读器考虑其他信号,例如可聚焦性或文本的存在,以决定它关注的内容。--> <attr name="screenReaderFocusable" format="boolean" />
下面的焦点指定通常并不需要设置,因为系统会自动检索焦点目标,除非你有特殊的需求
android:nextFocusForward="@+id/code_et" 下一个焦点目标
android:nextFocusUp="@id/book" 定义指定方向的焦点
android:nextFocusDown="@id/book" 定义指定方向的焦点
android:nextFocusLeft="@id/book" 定义指定方向的焦点
android:nextFocusRight="@id/book" 定义指定方向的焦点
android:nextClusterForward="@id/book" 定义下一个键盘导航集群
android:descendantFocusability属性
android:descendantFocusability是View的一个属性。可以理解是viewGroup和其子控件焦点相关的属性。
-
beforeDescendants :viewGroup会优先其子类控件而获取到焦点
-
afterDescendants :viewGroup只有当其子类控件不需要获取焦点时才获取焦点
-
blocksDescendants :viewGroup会覆盖子类控件而直接获得焦点
设置默认焦点
mBinding.piano.requestFocus()
监听某个view的焦点变化
获得焦点或者失去焦点
mBinding.piano.setOnFocusChangeListener { view, b -> Log.e("zh", "piano $b ") }
监听指定View的焦点按下的键值
mBinding.brightnessSeekBar.setOnKeyListener(View.OnKeyListener { view, i, keyEvent -> if (i == KeyEvent.KEYCODE_ENTER) { if (mUnfoldBrightnessLayout) { mUnfoldBrightnessLayout = false mBinding.brightnessLayout.isFocusable = true mBinding.brightnessLayout.isSelected = false mBinding.unfoldBrightnessGroup.visibility = View.GONE mBinding.brightnessLayout.requestFocus() animationUp(mBinding.brightnessIcon2) } true } false })
监听全局焦点
private val focusChangeListener: ViewTreeObserver.OnGlobalFocusChangeListener = object : ViewTreeObserver.OnGlobalFocusChangeListener { override fun onGlobalFocusChanged(oldFocus: View?, newFocus: View?) { Log.e("zh", "oldFocus ==" + oldFocus + " id:" + oldFocus?.id) Log.e("zh", "newFocus ==" + newFocus + " id:" + newFocus?.id) if (newFocus != null) { if (mBinding.viewPage.currentItem == 1 && (newFocus.id == R.id.hut || newFocus.id == R.id.tv || newFocus.id == R.id.song || newFocus.id == R.id.story) ) { mBinding.viewPage.currentItem = 0 return } if (mBinding.viewPage.currentItem == 1 && (newFocus.id == R.id.draw || newFocus.id == R.id.book || newFocus.id == R.id.piano || newFocus.id == R.id.chess) ) { mBinding.viewPage.currentItem = 2 return } if ((mBinding.viewPage.currentItem == 0 || mBinding.viewPage.currentItem == 2) && (newFocus.id == R.id.news || newFocus.id == R.id.lwlx || newFocus.id == R.id.time || newFocus.id == R.id.chest || newFocus.id == R.id.film || newFocus.id == R.id.applicationMarket || newFocus.id == R.id.weather || newFocus.id == R.id.music) ) { mBinding.viewPage.currentItem = 1 return } } } }
注册
override fun onCreate(savedInstanceState: Bundle?) { //略。。 mBinding.root.getViewTreeObserver().addOnGlobalFocusChangeListener(focusChangeListener) } override fun onDestroy() { super.onDestroy() mBinding.root.viewTreeObserver.removeOnGlobalFocusChangeListener(focusChangeListener) }
子View焦点状态跟随父布局
android:duplicateParentState="true"
TV开发中常用函数
/** * 设置焦点放大 */ fun View.setFocusEnlarge(float: Float) { this.setOnFocusChangeListener { view, b -> if (b) { this.scaleX = float this.scaleY = float } else { this.scaleX = 1.0f this.scaleY = 1.0f } } } /** * 鼠标选中放大 */ fun View.setHoverEnlarge(float: Float){ this.setOnHoverListener { v, event -> when(event.action){ MotionEvent.ACTION_HOVER_ENTER->{ this.scaleX = float this.scaleY = float } MotionEvent.ACTION_HOVER_EXIT->{ this.scaleX = 1.0f this.scaleY = 1.0f } MotionEvent.ACTION_HOVER_MOVE->{} } false } }
End
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/16082399.html