面对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[0] < 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<View>(R.id.btn_myself) ?: focused.rootView.findViewById<View>(R.id.btn_back) } else { scrollToPosition(0) super.onFocusSearchFailed(focused, focusDirection, recycler, state) } } } else { focused.rootView.findViewById<View>(R.id.btn_myself) } } else -> super.onFocusSearchFailed(focused, focusDirection, recycler, state) } } }
View Code
避免直接request或者clear焦点
来源链接:https://www.cnblogs.com/LiuZhen/p/18959703
© 版权声明
本站所有资源来自于网络,仅供学习与参考,请勿用于商业用途,否则产生的一切后果将由您(转载者)自己承担!
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
如有侵犯您的版权,请及时联系3500663466#qq.com(#换@),我们将第一时间删除本站数据。
THE END
暂无评论内容