实现类似YouTube的Fragment拖拽效果(draggable panel已废弃)
Alright, let's solve this problem of building a YouTube-like floating player—where your entire Fragment minimizes, leaving just the player view active and visible over other Fragments or Activities—now that the draggable panel library is deprecated. Here are two robust, modern solutions you can implement:
1. Jetpack WindowManager Library (Official & Recommended)
Google's Jetpack WindowManager is the go-to replacement for legacy window management code. It handles cross-device compatibility (including foldables) and follows Android's latest best practices.
Step-by-Step Implementation:
Add Dependency:
implementation "androidx.window:window:1.1.0" implementation "androidx.window:window-java:1.1.0" // For Java projectsInitialize WindowManager:
In your Fragment, create an instance ofWindowManagerand define layout parameters for your floating player:private lateinit var windowManager: WindowManager private lateinit var floatingPlayerView: View private val params = WindowManager.LayoutParams().apply { type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE } flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS width = WindowManager.LayoutParams.WRAP_CONTENT height = WindowManager.LayoutParams.WRAP_CONTENT gravity = Gravity.TOP or Gravity.START x = 100 y = 100 }Inflate & Attach Floating Player:
When the user taps to minimize the Fragment, inflate your player layout and add it to the window:floatingPlayerView = layoutInflater.inflate(R.layout.layout_floating_player, null) windowManager = requireContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager windowManager.addView(floatingPlayerView, params) // Hide your Fragment's main content binding.mainFragmentContent.visibility = View.GONEHandle Drag Functionality:
Add touch listeners to let users drag the player around the screen:var initialX = 0 var initialY = 0 var initialTouchX = 0f var initialTouchY = 0f floatingPlayerView.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { initialX = params.x initialY = params.y initialTouchX = event.rawX initialTouchY = event.rawY true } MotionEvent.ACTION_MOVE -> { params.x = initialX + (event.rawX - initialTouchX).toInt() params.y = initialY + (event.rawY - initialTouchY).toInt() windowManager.updateViewLayout(floatingPlayerView, params) true } else -> false } }Clean Up & Restore:
When restoring the Fragment, remove the floating view and show the main content again. Don't forget to clean up inonDestroyView()to avoid leaks:private fun restoreFragment() { if (::floatingPlayerView.isInitialized) { windowManager.removeView(floatingPlayerView) } binding.mainFragmentContent.visibility = View.VISIBLE } override fun onDestroyView() { super.onDestroyView() if (::floatingPlayerView.isInitialized) { windowManager.removeView(floatingPlayerView) } }
2. Custom WindowManager Implementation (Full Control)
If you need more granular control over the floating window's behavior, you can build a custom solution using the system WindowManager directly. This gives you full access to all layout parameters and window flags.
Key Notes:
- Permission: For Android 6.0+, request the
SYSTEM_ALERT_WINDOWpermission. Redirect users to app settings if denied:if (!Settings.canDrawOverlays(requireContext())) { val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:${requireContext().packageName}")) startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE) } - Lifecycle Binding: Tie the floating view's lifecycle to your Fragment/Activity to prevent leaks. Use
onPause()/onResume()to show/hide the player as needed. - Player State Sync: Keep the floating player's playback state (play/pause, progress) synced with your original Fragment's player. Use a ViewModel or singleton player manager for this.
Bonus: Picture-in-Picture (PiP) Mode
If you don't need full customization, Android's built-in PiP mode is a quick alternative. It lets your player stay visible over other apps, though layout control is limited:
- Add
android:supportsPictureInPicture="true"to your Activity inAndroidManifest.xml. - Call
enterPictureInPictureMode()when you want to minimize the player.
内容的提问来源于stack exchange,提问作者Raja

