当前位置: 首页 > article >正文

Flutter PIP 插件 ---- Android

在 Flutter Android 应用中实现画中画功能

画中画(Picture-in-Picture, PiP)模式允许您的应用在一个固定在屏幕角落的小窗口中运行,同时用户可以与其他应用进行交互。本指南将介绍如何在 Flutter Android 应用中实现画中画功能,包括其局限性和解决方案。

项目地址

flutter_pip

前提条件

  • 需要 Android 8.0 (API level 26) 或更高版本才能完全支持画中画功能

  • 基本的 Flutter 插件开发知识

  • 基本的 Android 开发知识

实现概述

实现包含两个主要组件:

  1. FlutterPipController: 处理画中画功能和状态管理

  2. FlutterPipPlugin: 桥接 Flutter 和原生 Android 代码

主要特性

  • 画中画模式支持检测

  • 自定义宽高比配置

  • 平滑过渡的源矩形提示

  • 画中画状态监控和回调

  • 非视频内容的交叉淡入淡出动画

核心实现

1. 检查画中画支持

在使用画中画之前,我们需要检查设备是否支持:

public boolean isSupported() {Activity activity = mActivity.get();if (activity == null) {return false;}// Requires Android 8.0 (API 26) or higherif (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {return false;}final PackageManager pm = activity.getApplicationContext().getPackageManager();return pm != null && pm.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
}

2. 配置画中画参数

画中画模式可以自定义几个参数:

public boolean setup(@Nullable Rational aspectRatio,@Nullable Boolean autoEnterEnabled,@Nullable Rect sourceRectHint) {// ... version checks and null checks ...PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder();if (aspectRatio != null) {builder.setAspectRatio(aspectRatio);}if (sourceRectHint != null) {builder.setSourceRectHint(sourceRectHint);}// Disable seamless resize for non-video contentbuilder.setSeamlessResizeEnabled(false);activity.setPictureInPictureParams(builder.build());
}

Flutter 集成限制和解决方案

1. 自动进入画中画模式限制

Flutter 不正确地委托 Android 生命周期事件,如 onPauseonPiPModeChanged。这给实现自动进入画中画模式带来了挑战。

限制:

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
public boolean isAutoEnterSupported() {// We could support this on Android 12+, but Flutter limitations prevent itreturn false;
}

解决方案:
我们不依赖自动进入画中画模式,而是提供显式的方法来进入和退出画中画模式,这些方法可以从 Flutter 代码中调用:

public boolean start() {if (!isSupported() || isActived() || !isPipEnabled()) {return false;}Activity activity = mActivity.get();if (activity == null) {return false;}activity.enterPictureInPictureMode(mParamsBuilder.build());return true;
}

2. 画中画状态变化检测

由于 Flutter 不提供画中画状态变化事件,我们实现了一个轮询机制来检测状态变化。

解决方案:

private void startStateMonitoring() {// Poll every 100ms to check PiP statemCheckStateTask = new Runnable() {@Overridepublic void run() {checkPipState();mHandler.postDelayed(this, CHECK_INTERVAL_MS);}};mHandler.post(mCheckStateTask);
}

3. 画中画退出处理

Android 不提供直接退出画中画模式的方法。

解决方案:

public void stop() {if (!isSupported() || !isActived()) {return;}Activity activity = mActivity.get();if (activity == null) {return;}// Move the activity to background instead of truly stopping PiPactivity.moveTaskToBack(false);
}

最佳实践

  1. 资源管理: 始终正确释放资源:
public void dispose() {stopStateMonitoring();mPipParams = null;mParamsBuilder = null;mHandler = null;mLastPipState = false;mCheckStateTask = null;
}
  1. 状态监控: 跟踪画中画状态变化并通知 Flutter:
private void checkPipState() {boolean currentState = isActived();if (currentState != mLastPipState) {mLastPipState = currentState;notifyPipStateChanged(currentState ? PipState.Started : PipState.Stopped);}
}
  1. 交叉淡入淡出动画: 对于非视频内容,禁用无缝调整大小:
mParamsBuilder.setSeamlessResizeEnabled(false);

结论

虽然在 Flutter Android 应用中实现画中画功能受到 Flutter 处理 Android 生命周期事件的一些限制,但我们可以通过轮询状态检测和显式控制方法来解决这些问题。这里提供的解决方案提供了一个可靠且稳定的实现,同时保持良好的用户体验。

请记住要在不同的 Android 版本和设备配置上进行全面测试,因为画中画行为在不同的 Android 实现中可能会有所不同。

参考

  • Android 官方文档 - 画中画

PS

这个项目会持续维护下去,而且已经在准备发布pub.dev, 目前上面的文档是AI帮助生成的,有些不太准确和完善,但基本路线是对的,后续会持续补充完善。

相关文章:

Flutter PIP 插件 ---- Android

在 Flutter Android 应用中实现画中画功能 画中画(Picture-in-Picture, PiP)模式允许您的应用在一个固定在屏幕角落的小窗口中运行,同时用户可以与其他应用进行交互。本指南将介绍如何在 Flutter Android 应用中实现画中画功能,包括其局限性和解决方案。 项目地址 flutter_p…...

基于DeepSeek API和VSCode的自动化网页生成流程

1.创建API key 访问官网DeepSeek &#xff0c;点击API开放平台。 在开放平台界面左侧点击API keys&#xff0c;进入API keys管理界面&#xff0c;点击创建API key按钮创建API key&#xff0c;名称自定义。 2.下载并安装配置编辑器VSCode 官网Visual Studio Code - Code Editing…...

结合实际讲NR系列2—— SIB1

这是在基站抓取的sib1的一条信令 L3MessageContent BCCH-DL-SCH-Messagemessagec1systemInformationBlockType1cellSelectionInfoq-RxLevMin: -64q-QualMin: -19cellAccessRelatedInfoplmn-IdentityListPLMN-IdentityInfoplmn-IdentityListPLMN-IdentitymccMCC-MNC-Digit: 4MC…...

信创领域的PostgreSQL管理员认证

信创产业&#xff0c;全称为信息技术应用创新产业&#xff0c;是中国为应对国际技术竞争、保障信息安全、实现科技自立而重点发展的战略性新兴产业。其核心目标是通过自主研发和生态构建&#xff0c;逐步替代国外信息技术产品&#xff0c;形成自主可控的国产化信息技术体系。 发…...

AI基础 -- AI学习路径图

人工智能从数学到大语言模型构建教程 第一部分&#xff1a;AI 基础与数学准备 1. 绪论&#xff1a;人工智能的过去、现在与未来 人工智能的定义与发展简史从符号主义到统计学习、再到深度学习与大模型的变迁本书内容概览与学习路径指引 2. 线性代数与矩阵运算 向量与矩阵的…...

使用 Visual Studio Code (VS Code) 开发 Python 图形界面程序

安装Python、VS Code Documentation for Visual Studio Code Python Releases for Windows | Python.org 更新pip >python.exe -m pip install --upgrade pip Requirement already satisfied: pip in c:\users\xxx\appdata\local\programs\python\python312\lib\site-pa…...

IEEE期刊Word导出PDF注意事项

在系统上提交论文时候一般要求PDF文档&#xff0c;但是word直接转PDF可能存在一些问题&#xff1a; 部分图片不清晰。字体未嵌入PDF。间距发生了变化。字体发生了变化。一张图片显示不完全。 下面介绍word转PDF最稳妥的技巧以及如何实现全部字体的嵌入。 1. 操作流程 ① 另…...

针对Prompt优化的深入分析

一、针对Prompt优化的深入分析 1. 结构化设计 技术原理&#xff1a; 大语言模型&#xff08;LLMs&#xff09;本质是基于概率的序列生成器&#xff0c;结构化模板通过显式定义输出框架&#xff08;如角色、段落数、连接词&#xff09;&#xff0c;利用模型的模式匹配能力&…...

flutter ListView 局部刷新

在 Flutter 中&#xff0c;要仅刷新 ListView 中的某一列&#xff08;即特定列表项&#xff09;&#xff0c;可以通过以下步骤实现&#xff1a; 核心思路 为每个列表项分配唯一标识&#xff08;如 Key&#xff09;&#xff0c;帮助 Flutter 识别需要更新的项。 局部状态管理&a…...

如何在 Elasticsearch 中设置向量搜索 - 第二部分

作者&#xff1a;来自 Elastic Valentin Crettaz 了解如何在 Elasticsearch 中设置向量搜索并执行 k-NN 搜索。 本文是三篇系列文章中的第二篇&#xff0c;深入探讨了向量搜索&#xff08;也称为语义搜索&#xff09;的复杂性以及它在 Elasticsearch 中的实现方式。 第一部分重…...

DeepSeek的出现会对百度有多大影响?

当DeepSeek与ChatGPT等大模型接管搜索入口&#xff0c;我们正见证百年一遇的信息革命。 01 传统搜索已死&#xff1f;AI助手正在重写游戏规则&#xff01; 当DeepSeek与ChatGPT等大模型接管搜索入口&#xff0c;我们正见证百年一遇的信息革命。 就像汽车淘汰马车、触屏终结按键…...

【C#】条件运算符

1.逻辑与(&&) Console.WriteLine(true && true);//true Console.WriteLine(true && false);//false Console.WriteLine(false && false);//false2.逻辑或(||) Console.WriteLine(true || true);//true Console.WriteLine(true || false);//t…...

单例模式详解(Java)

单例模式详解(Java) 一、引言 1.1 概述单例模式的基本概念和重要性 单例模式是一种常用的软件设计模式,它确保一个类在整个应用程序中只有一个实例,并提供一个全局访问点来访问这个唯一实例。这种模式在资源管理、配置设置和日志记录等方面非常有用,因为它们通常只需要…...

PyQt学习记录01——加法计算器

目录 PyQt学习记录01——加法计算器 PyQt学习记录02——串口助手 0. 安装配置 0.1 安装相关库 首先打开你的PyCharm程序&#xff0c;然后新建一个目录用于学习&#xff0c;其次在terminal中输入 pip install pyqt5如果你不具有科学上网能力&#xff0c;请改为国内源 pip …...

笔记:蓝桥杯python搜索(3-2)——DFS剪支和记忆化搜索

目录 一、DFS剪支 二、例题 P2942 数字王国之军训军队 P3075 特殊的多边形 三、记忆化搜索 四、例题 例题 P3820 混境之地 P216 地宫取宝 一、DFS剪支 在搜索过程中&#xff0c;如果需要完全遍历所有情况可能需要很多时间在搜索到某种状态时&#xff0c;根据当前状态判断…...

k8s启空容器用于排查问题

如果 Pod 一会儿就销毁了&#xff0c;可能是由于 Pod 配置、节点状态或容器运行时问题导致的。 此时想进容器排查&#xff0c;但是pod一会儿就销毁了&#xff0c;不利于排查。 为了排查问题&#xff0c;可以启动一个空容器来临时保留 Pod&#xff0c;进而进入 Pod 内部进行调…...

jenkins备份还原配置文件

下载ThinBackup插件 方式1 从插件市场直接下载 Manage Jenkins->Manage Plugins->可选插件搜索 注意&#xff1a;有时可能因为网络或者版本问题下载不了&#xff0c;好像是默认下载最新版本&#xff0c;可选择手动安装&#xff01; 方式二 手动安装插件 点击查看手…...

02.11 数据库

1.思维导图 2.题目 将 epoll 服务器、客户端拿来用客户端&#xff1a;写一个界面&#xff0c;里面有注册登录服务器&#xff1a;处理注册和登录逻辑&#xff0c;注册的话将注册的账号密码写入数据库&#xff0c;登录的话查询数据库中是否存在账号&#xff0c;并验证密码是否正…...

物联网(IoT)如何与人工智能(AI)的结合

物联网&#xff08;IoT&#xff09;与人工智能&#xff08;AI&#xff09;的结合是当前技术发展的重要趋势&#xff0c;通常被称为 AIoT&#xff08;人工智能物联网&#xff09;。这种结合通过将AI的计算能力和数据分析能力与物联网的海量设备连接能力相结合&#xff0c;实现了…...

嵌入式硬件篇---原码、补码、反码

文章目录 前言简介八进制原码、反码、补码1. 原码规则示例问题 2. 反码规则示例问题 3. 补码规则示例优点 4. 补码的运算5. 总结 十六进制原码、反码、补码1. 十六进制的基本概念2. 十六进制的原码规则示例 3. 十六进制的反码规则示例 4. 十六进制的补码规则示例 5. 十六进制补…...

PHP函数fgetc(): 从文件中读取一个字符

在PHP中&#xff0c;有许多用于文件操作的函数&#xff0c;其中之一就是fgetc()函数。fgetc()函数用于从打开的文件中读取一个字符&#xff0c;并将指针移动到下一个字符的位置。本文将介绍fgetc()函数的用法&#xff0c;并提供一些示例来帮助读者更好地理解和使用这个函数。 …...

Spring Boot整合DeepSeek实现AI对话(API调用和本地部署)

本篇文章会分基于DeepSeek开放平台上的API&#xff0c;以及本地私有化部署DeepSeek R1模型两种方式来整合使用。 本地化私有部署可以参考这篇博文 全面认识了解DeepSeek利用ollama在本地部署、使用和体验deepseek-r1大模型 Spring版本选择 根据Spring官网的描述 Spring AI是一…...

苹果转型独立AR眼镜:一场技术与创新的深度探索

在科技日新月异的今天,增强现实(AR)技术正逐渐从科幻电影走进我们的日常生活。作为科技界的领头羊,苹果公司的每一步动向都备受关注。近期,苹果宣布暂停原定的Mac连接式AR眼镜计划,转而全力研发一款独立的AR眼镜。这一战略调整不仅反映了苹果对AR市场的深度洞察,也预示着…...

Java小白入门基础知识(一)

1.初识Java java源程序通过javac 编译生成字节码文件&#xff0c;通过java命令运行java程序 总结&#xff1a; 1&#xff09;在一个Java文件中&#xff0c;只能有一个public class 2&#xff09;public class一定要和文件名一致 3&#xff09;类里面包含方法 4&#xff09…...

通过 Docker 安装和部署 KeyDB v6.3.4 的详细步骤

KeyDB 是一种高性能的开源内存数据库&#xff0c;最初是基于 Redis 项目开发的&#xff0c;但在性能、特性和功能上进行了许多增强和改进。它兼容 Redis 的大部分命令和数据结构&#xff0c;因此可以作为 Redis 的替代品使用&#xff0c;尤其是在需要更高性能和多线程支持的场景…...

【JavaEE进阶】依赖注入 DI详解

目录 &#x1f334;什么是依赖注入 &#x1f384;依赖注入的三种方法 &#x1f6a9;属性注⼊(Field Injection) &#x1f6a9;Setter注入 &#x1f6a9;构造方法注入 &#x1f6a9;三种注⼊的优缺点 &#x1f333;Autowired存在的问题 &#x1f332;解决Autowired存在的…...

Avnet RFSoC基于maltab得5G 毫米波 开发工具箱

使用 MATLAB 连接到 AMD Zynq™ RFSoC 评估板。使用 RF 附加卡执行 OTA 测试。使用 HDL Coder 部署算法 版本要求&#xff1a; 大于 2023b 需要以下支持包之一&#xff1a; 适用于 Xilinx 基于 Zynq 的无线电&#xff08;R2023b 及更早版本&#xff09;的通信工具箱支持包适…...

掌握 PHP 单例模式:构建更高效的应用

在 PHP 应用开发中&#xff0c;资源的高效管理至关重要。单例模式是一种能够帮助我们实现这一目标的设计模式。本文将深入探讨单例模式的概念、工作原理以及在 PHP 项目中何时应该&#xff08;或不应该&#xff09;使用它。 什么是单例模式&#xff1f; 单例模式是一种设计模…...

neo4j-解决导入数据后出现:Database ‘xxxx‘ is unavailable. Run :sysinfo for more info.

目录 问题描述 解决方法 重新导入 问题描述 最近在linux上部署了neo4j&#xff0c;参照之前写的博客:neo4j-数据的导出和导入_neo4j数据导入导出-CSDN博客 进行了数据导出、导入操作。但是在进行导入后&#xff0c;重新登录网页版neo4j&#xff0c;发现对应的数据库状态变…...

卷积神经网络(CNN)池化层的最大池化(Max Pooling)和 平均池化(Average Pooling)

在 卷积神经网络(CNN) 中,池化层(Pooling Layer) 是用来 减少特征图的空间尺寸、减少计算量、控制过拟合 的关键层。池化层通过 窗口操作 将输入特征图中一定区域的信息压缩成一个单一的值,常见的池化方式有 最大池化(Max Pooling) 和 平均池化(Average Pooling)。这…...