Floating small windows are still relatively common requirements in live broadcast projects. Open other interfaces in the live room or exit to the desktop to continue playing live content. The following is my implementation plan.
Realization ideas
In fact, it is easy to think through WindowManager
the addView()
implementation, but requires the user's consent permissions floating window, if your project is a floating window within the application, you can go to get DecorView
to it to add a View
so will not have to obtain the permission
Floating window permission acquisition
manifest
Add permissions
<!-- 悬浮窗权限-->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
To Window
set up some type
type, where there is a change after the 8.0 version of the type to be a judge here
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
}
Judgment of authority
The floating window needs to be opened manually by the user, and here needs to be a guide for the user
if (!Settings.canDrawOverlays(this)) { // 判断是否有权限
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
// packageName 是应用的包名
intent.data = Uri.parse("package:$packageName")
// 直接打开系统的同意界面给用户操作
startActivityForResult(intent, REQ_CODE_1000)
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQ_CODE_1000) {
if (Settings.canDrawOverlays(this)) {
// 用户同意了就可以进行其它操作了
}
}
}
Handling sliding and inertial sliding
The slide is treated by WindowManager
the updateViewLayout()
method according to the distance slide change Window
of position, but the process to calculate whether the slide before sliding distance can slide over the border, can not let go of the floating window outside the screen go
Inertial sliding is the template code, hand it over to GestureDetector
the onFling()
method, and then OverScroller
calculate the current sliding value
One more thing to note, our floating window not only handles the sliding time but also the click event. When the user clicks on the window, it also returns to the live page . The click event will not work when the front is onTouchEvent
handed over GestureDetector
to handle it. , That is, the setOnClickListener
setting has no effect, here you have to manually adjust this callback
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
// 触发 onClick() 回调
performClick()
return true
}
Packaging ideas
The floating window has some variable parts and unchanging parts. The variable is the style of the floating window and the specific playback operation. The unchanging is the sliding operation, so the two parts are separated and the two parts are connected using the adapter mode. In the adapter, users can customize the layout and implement their own business logic. Since the floating window has a global effect, there can only be one at a time, so a singleton class is used FloatWindow
to manage the addition and deletion of View.
// 创建 FloatView 设置 Adapter
val floatView = FloatView(this).apply {
setAdapter(SimpleAdapter())
}
// 把 View 设置给 Window
FloatWindow.getInstance(this).bindView(floatView)
// 移除 Window
FloatWindow.getInstance(this).removeView()