如何在初始化activity的时候使listView获取焦点

在上一次用RecycleView的时候,鄙渣也遇到了焦点问题。可以看看这里:Fragment中的RecycleView的转场动画与保存焦点。

这两个问题详细描述实际上是一样的,鄙渣需要在Acitivity创建完成后立即指定ListView(RecycleView)中的某一个子item获取焦点。在链接中的那篇文章中提到了 viewTreeObserver 这一工具,但是鄙渣最终并没有采用,而是使用了RecycleView.Adapter中的两个方法—— onAttachedToRecyclerViewonDetachedFromRecyclerView 两个回调。这两个回调即可判断出RecycleView被初始化和被销毁的时间节点,并进行相关操作。

override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
    super.onAttachedToRecyclerView(recyclerView)
    thisRecyclerView = recyclerView
}

override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
    super.onDetachedFromRecyclerView(recyclerView)
    thisRecyclerView = null
}
    
override fun onBindViewHolder(holder: FaqViewHolder, position: Int) {
    ...
    if (position == latestPosition) {
        thisRecyclerView?.smoothScrollToPosition(latestPosition)
        faqItemContainer.requestFocus()
    }

    ...
    faqItemContainer.setOnFocusChangeListener { _, hasFocus ->
        if (hasFocus) {
            latestPosition = position
        }
    }
}

companion object {
    var latestPosition = 0
}

在这次的问题中,遇到了一个棘手的问题,ListView中没有 onAttachedToRecyclerViewonDetachedFromRecyclerView 这两个方法。那么难道又得用 viewTreeObserver 吗?

当然不!上次使用糟糕体验让鄙渣有了十分难受的回忆。所以这次鄙渣选择另寻新方法。在本文一开始已经点明了主要问题——如何判断Activity已经初始化完成 。在这里鄙渣也找到了两个方法,都是用于判断是否初始化完成的。

一个方法来源于Android 判断 activity 初始化是否完成 中提到的,使用WindowToken来判断是否初始化完成。不过他的写法稍微有些暴力,大概如下:

class XXXActivity : Activity(){
    ...
    private var focusHandler: Handler? = null
    ...
    
    class RequestListViewFocusHandler(private val weakReference: WeakReference) : Handler() {
        override fun handleMessage(msg: Message?) {
            super.handleMessage(msg)
            val activity = weakReference.get()
            activity?.let {
                if (it.window.decorView.windowToken != null) {
                    Logger.d("token不为空,请求焦点")
                    it.listViewChangeAndFocus()
                    //这里的listView直接是id,kotlin中封装好了这种操作,不需要findviewbyid了
                    it.listView.setSelection(0)
                } else {
                    sendEmptyMessageDelayed(REFRESH_FOCUS, 100)
                    Logger.d("token为空")
                }
            }
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        focusHandler = RequestListViewFocusHandler(WeakReference(this))
        (focusHandler as RequestListViewFocusHandler).sendEmptyMessageDelayed(REFRESH_FOCUS,100)
        ...
    }
}

这种写法确实能够做到刷新焦点,几乎也能做到实时刷新,但是这种不断发消息轮询的策略总归不大优雅。所以在启硕哥的帮助下,我又发现了第二种方式: onWindowFocusChanged

在关于android activity加载完毕事件这篇文章里其实有说这一类问题的原因了,并且给出的解决方法就是 onWindowFocusChanged 。实现代码如下:

override fun onWindowFocusChanged(hasFocus: Boolean) {
    if (hasFocus){
        listViewChangeAndFocus()
        listView.setSelection(0)
    }
}

这样一来就简洁优雅了许多,并且不需要再花里胡哨地找其他的方法了。

你可能感兴趣的:(如何在初始化activity的时候使listView获取焦点)