TV RecyclerView 焦点处理笔记
面对RecyclerView焦点,特别是复杂视图,多类型情况下,需求有时候不按系统定义的走,比如要求首次落焦在第二个,或者焦点移动到边界就不能移动如果不遵循焦点流程直接粗暴处理,会导致系统分发事件出异常,焦点乱飞
默认焦点使用 addOnChildAttachStateChangeListener 监听
recyclerView.addOnChildAttachStateChangeListener(object :
RecyclerView.OnChildAttachStateChangeListener {
override fun onChildViewAttachedToWindow(view: View) {
val position = recyclerView.getChildAdapterPosition(view)
log("position $position view $view")
if (position == 3) view.requestFocus()
}
override fun onChildViewDetachedFromWindow(view: View) {
}
})View Code对于超出边界时,系统会触发onFocusSearchFailed
override fun onFocusSearchFailed(
focused: View,
focusDirection: Int,
recycler: RecyclerView.Recycler,
state: RecyclerView.State
): View? {
return when (focusDirection) {
View.FOCUS_UP -> {
if (focused.parent.parent is RecyclerView) {
val position = (focused.parent as? View)?.let { getPosition(it) } ?: -1
//...
} else {
focused.rootView.findViewById<View>(R.id.btn_myself)
}
}
else -> super.onFocusSearchFailed(focused, focusDirection, recycler, state)
}
}View Code针对焦点移动时自动滚动列表到可见位置,可以使用 onRequestChildFocus
override fun onRequestChildFocus(
parent: RecyclerView,
state: RecyclerView.State,
child: View,
focused: View?
): Boolean {
val position = parent.getChildAdapterPosition(child)
scrollToPosition(position)
return super.onRequestChildFocus(parent, state, child, focused)
}View Code如果针对焦点到边界位置后不能移动,或者边界触底动效,可以使用焦点拦截 onInterceptFocusSearch
完整代码
class ScreenMainGridManager(private val mAdapter: BaseAdapter, context: Context) : GridLayoutManager(context, 4) { private val marginStart = context.resources.getDimension(R.dimen.common_dp_54) init { spanSizeLookup = object : SpanSizeLookup() { override fun getSpanSize(position: Int): Int { val viewType = mAdapter.getItemViewType(position) return when (viewType) { ViewType.TITLE.value, ViewType.BANNER.value -> 4 else -> 1 } } } } override fun onInterceptFocusSearch(focused: View, direction: Int): View? { return when (direction) { View.FOCUS_LEFT -> { findLeftFocusView(focused) ?: super.onInterceptFocusSearch(focused, direction) } View.FOCUS_RIGHT -> { var isRightFocus = false findRecyclerView(focused)?.let { findRootView(focused)?.let { root -> val position = it.getChildAdapterPosition(root) if (position > 0 && position + 1 < itemCount) { val viewType = mAdapter.getItemViewType(position + 1) if (viewType == ViewType.TITLE.value) { isRightFocus = true } } else if (position + 1 == itemCount) { isRightFocus = true } } } if (isRightFocus) focused else super.onInterceptFocusSearch(focused, direction) } else -> super.onInterceptFocusSearch(focused, direction) } } private fun findLeftFocusView(focused: View): View? { findRecyclerView(focused)?.let { val location = IntArray(2) focused.getLocationOnScreen(location) if (location < marginStart) { return focused } } return null } private fun findRecyclerView(focused: View): RecyclerView? { var parent: ViewParent? = focused.parent for (i in 0 until 2) { if (parent is RecyclerView) break parent = parent?.parent } return parent as? RecyclerView } /** item root view */ private fun findRootView(focused: View): View? { var result: View? = focused var parent = focused.parent for (i in 0 until 2) { if (parent is RecyclerView) { return result } result = parent as? View parent = parent?.parent } return result } override fun onRequestChildFocus(
parent: RecyclerView,
state: RecyclerView.State,
child: View,
focused: View?
): Boolean {
val position = parent.getChildAdapterPosition(child)
scrollToPosition(position)
return super.onRequestChildFocus(parent, state, child, focused)
} override fun onFocusSearchFailed( focused: View, focusDirection: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State ): View? { return when (focusDirection) { View.FOCUS_UP -> { if (focused.parent.parent is RecyclerView) { val position = (focused.parent as? View)?.let { getPosition(it) } ?: -1 if (position < 0) { super.onFocusSearchFailed(focused, focusDirection, recycler, state) } else { val item = mAdapter.getItem(position) if (item is MainBannerItem || item is MeAddItem) { focused.rootView.findViewById(R.id.btn_myself) ?: focused.rootView.findViewById(R.id.btn_back) } else { scrollToPosition(0) super.onFocusSearchFailed(focused, focusDirection, recycler, state) } } } else { focused.rootView.findViewById(R.id.btn_myself) } } else -> super.onFocusSearchFailed(focused, focusDirection, recycler, state) } }}View Code避免直接request或者clear焦点
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]