在Android的WindowManager中添加ComposeView的流程及注意事项

发布于:2024-05-22 ⋅ 阅读:(128) ⋅ 点赞:(0)

在Android的WindowManager中添加ComposeView的流程及注意事项

流程

总体跟普通的View一样设置窗口参数再用addView添加到WIndowManager中


    private val wm by lazy { MobilePlatformPlugin.applicationContext.getSystemService(WINDOW_SERVICE) as WindowManager }


    fun showPopWindow(context: Context) {
        val params = WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT, // 宽度
            WindowManager.LayoutParams.MATCH_PARENT, // 高度
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, // 窗口类型 TODO: //API Level
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // 窗口标志
            PixelFormat.TRANSLUCENT // 像素格式
        )

        composeView = ComposeView(context = context).apply {
            setContent {
                PopWindowView()
            }
        }
        lifecycleOwner = MyComposeViewLifecycleOwner().also {
            it.onCreate() // 注意
            it.attachToDecorView(composeView)
        }
        wm.addView(composeView, params)
        lifecycleOwner?.onStart()
        lifecycleOwner?.onResume()

    }

不过ComposeView需要有LifeCycleOwner的支持,不然运行会崩溃,所以需要自定义一个LifeCycleOwner,完全照抄下面这个即可,这里我也是抄的哈哈

    private class MyComposeViewLifecycleOwner : LifecycleOwner, ViewModelStoreOwner,
        SavedStateRegistryOwner {

        private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
        private val savedStateRegistryController = SavedStateRegistryController.create(this)
        private val store = ViewModelStore()

        override val lifecycle: Lifecycle
            get() = lifecycleRegistry
        override val savedStateRegistry: SavedStateRegistry
            get() = savedStateRegistryController.savedStateRegistry
        override val viewModelStore: ViewModelStore
            get() = store


        fun onCreate() {
            savedStateRegistryController.performRestore(null)
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
        }

        fun onStart() {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
        }

        fun onResume() {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
        }

        fun onPause() {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        }

        fun onStop() {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
        }

        fun onDestroy() {
            lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
            store.clear()
        }

        /**
         * Compose uses the Window's decor view to locate the
         * Lifecycle/ViewModel/SavedStateRegistry owners.
         * Therefore, we need to set this class as the "owner" for the decor view.
         */
        fun attachToDecorView(decorView: View?) {
            decorView?.let {
                it.setViewTreeViewModelStoreOwner(this)
                it.setViewTreeLifecycleOwner(this)
                it.setViewTreeSavedStateRegistryOwner(this)
            } ?: return
        }
    }

注意事项

这里需要注意一个非常关键的点,有一些资料只执行了LifeCycleOwner的create事件,只执行create事件可能会导致Compose的状态监听失效,所以最后一定要模拟start和resume事件,一定要在addView后添加

lifecycleOwner?.onStart()
lifecycleOwner?.onResume()

这个坑有点大,研究了挺久才发现,所以放出来希望能帮助到遇到同样问题的人们。

销毁

最后关闭悬浮窗也记得执行一下pause,stop,destroy流程

    fun closePopWindow() {
        if (composeView?.isAttachedToWindow != true) return
        wm.removeView(composeView)
        composeView = null
        lifecycleOwner?.onPause()
        lifecycleOwner?.onStop()
        lifecycleOwner?.onDestroy()
        lifecycleOwner = null
    }