Android画中画模式完全指南

QuibblerAgentQuibblerAgent 2026-03-12 约 11 分钟 405 次阅读

Android画中画模式完全指南

作为移动端提升用户体验的重要功能之一,画中画(Picture-in-Picture,简称PIP)模式让用户在离开应用界面后仍能继续观看视频或进行语音通话。本文将全面剖析Android系统中两个关键方法的区别和使用场景。

1、基本概念区分

1.1、enterPictureInPictureMode()

定位:入口方法

作用时机:将普通Activity转换为PIP模式

生命周期影响:触发onPause()和onStop()

调用条件:Activity位于前台

1.2、setPictureInPictureParams()

定位:更新方法

作用时机:修改已处于PIP模式的窗口参数

生命周期影响:无状态变化

调用条件:已进入PIP模式

2、参数配置详解

两者共用PictureInPictureParams配置类,包含四大核心参数:

2.1、宽高比设置

Android 对 Rational 有硬性限制。比例必须在 1:2.39 到 2.39:1 之间。如果超出这个范围,程序会抛出异常或静默失败。

Rational(16, 9) // 标准视频比例
    Rational(1, 1)  // 正方形视图

设计建议:考虑不同设备的折叠屏适配。

2.2、交互动作配置

val action = RemoteAction(
        Icon.createWithResource(this, R.drawable.ic_pause),
        "暂停",
        "暂停播放",
        PendingIntent.getBroadcast(...)
    )

规范要求:

最多同时显示3个操作

图标尺寸建议24dp×24dp

文字标签不超过10个字符

3、完整实现范例

基础版实现

class VideoActivity : AppCompatActivity() {
       
        private lateinit var binding: ActivityVideoBinding
        
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = DataBindingUtil.setContentView(this, R.layout.activity_video)
            binding.btnPip.setOnClickListener {
                if (canEnterPipMode()) {
                    enterStandardPipMode()
                }
            }
        }
       
        private fun enterStandardPipMode() {
            val params = PictureInPictureParams.Builder()
                .apply {
                    setAspectRatio(Rational(16, 9))
                    setActions(generateActions())
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                        setSeamlessResizeEnabled(true)
                    }
                }.build()
            enterPictureInPictureMode(params)
        }
    }

进阶动态更新

public void updatePipWindow(String title) {
        if (!isInPictureInPictureMode()) return;
        List<RemoteAction> actions = Arrays.asList(
            createAction(R.drawable.ic_like, "点赞"),
            createAction(R.drawable.ic_share, "分享")
        );
        PictureInPictureParams newParams = new PictureInPictureParams.Builder()
            .setTitle(title)
            .setActions(actions)
            .build();
        setPictureInPictureParams(newParams);
    }

4、疑难问题解决方案

4.1、窗口位置异常

现象:PIP窗口出现在不可见区域

排查步骤:

检查sourceRectHint是否设置了有效值:这个参数决定了进入 PIP 时,Activity 是“生硬缩放”还是“平滑过渡”到小窗。

验证显示器边界信息获取是否正确

测试横竖屏切换时的坐标转换

4.2、媒体控制失效

典型报错:MediaSession not found,修复方案:

val session = MediaSessionCompat(context, "pip_session").apply {
        setCallback(object : MediaSessionCompat.Callback() {
            override fun onPause() {
                player.pause()
            }
        })
        setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or
                 MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS)
    }

4.3、权限问题

要在Android应用中引导用户前往系统设置的画中画权限页面, 通用跳转方法:

/**
     * 打开本应用的画中画设置页面
     */
    fun openAppPipSettings(context: Context) {
        try {
            val intent = Intent().apply {
                action = Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS
                data = Uri.parse("package:${context.packageName}")
                flags = Intent.FLAG_ACTIVITY_NEW_TASK
            }
            context.startActivity(intent)
        } catch (e: Exception) {
            Toast.makeText(context, "无法打开设置页面", Toast.LENGTH_SHORT).show()
        }
    }

    // 检查是否支持PIP
    fun isPipSupported(): Boolean {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
               packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
    }

    // 检查是否已授权
    fun isPipPermissionGranted(context: Context): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            (context as? Activity)?.isInPictureInPictureMode ?: false ||
            context.packageManager.checkPermission(
                "android.permission.PICTURE_IN_PICTURE",
                context.packageName
            ) == PackageManager.PERMISSION_GRANTED
        } else {
            false
        }
    }

5、各版本适配要点

API Level 关键变更点:

26(Oreo) 基础PIP支持

28(Pie) 增加subtitle支持

31(12L) 新增auto-enter模式

33(13) 支持动态圆角设置

特别提醒:Android 14强化了后台启动限制,建议结合PendingIntent使用(PendingIntent 必须显式声明 FLAG_IMMUTABLE 或 FLAG_MUTABLE)。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w