Flutter PIP 插件 ---- Android
在 Flutter Android 应用中实现画中画功能
画中画(Picture-in-Picture, PiP)模式允许您的应用在一个固定在屏幕角落的小窗口中运行,同时用户可以与其他应用进行交互。本指南将介绍如何在 Flutter Android 应用中实现画中画功能,包括其局限性和解决方案。
项目地址
flutter_pip
前提条件
-
需要 Android 8.0 (API level 26) 或更高版本才能完全支持画中画功能
-
基本的 Flutter 插件开发知识
-
基本的 Android 开发知识
实现概述
实现包含两个主要组件:
-
FlutterPipController
: 处理画中画功能和状态管理 -
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 生命周期事件,如 onPause
和 onPiPModeChanged
。这给实现自动进入画中画模式带来了挑战。
限制:
@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);
}
最佳实践
- 资源管理: 始终正确释放资源:
public void dispose() {stopStateMonitoring();mPipParams = null;mParamsBuilder = null;mHandler = null;mLastPipState = false;mCheckStateTask = null;
}
- 状态监控: 跟踪画中画状态变化并通知 Flutter:
private void checkPipState() {boolean currentState = isActived();if (currentState != mLastPipState) {mLastPipState = currentState;notifyPipStateChanged(currentState ? PipState.Started : PipState.Stopped);}
}
- 交叉淡入淡出动画: 对于非视频内容,禁用无缝调整大小:
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…...
【20250211】字符串:459.重复的子字符串
#方法一:暴力求解法 # class Solution: # def repeatedSubstringPattern(self, s): # n len(s) # substr "" # #只重复一次不算“重复多次” # if n < 1: # return False # else: # …...

【DeepSeek学Cuda】矩阵转置:行读取优先还是列读取优先。
目录 **1. 实现A(按行读取,按列存储)2. 实现B(按列读取,按行存储)**3. 哪种更好 Professional cuda programming5. "当L1缓存被禁用时,所有内存访问都直接指向全局内存(Global …...

如何将3DMAX中的3D文件转换为AutoCAD中的2D图形?
大家好,今天我们来探讨一下如何将3DMAX中的3D文件转换为AutoCAD中的2D图形。无论是出于设计交流、施工准备还是其他实际需求,这种转换在工程设计领域都是一项非常实用的技能。接下来,我将为大家详细介绍几种实现这一转换的方法,帮助大家轻松跨越3D与2D设计之间的鸿沟。让我…...
Softhsm储存安全数据性能整理
目标:存储百万条数据对象 测试方案一:总大小2GB,每个数据对象大小约512KB,总条数4096条; 测试方案一:总大小2GB,每个数据对象大小约256B,总条数8388608条; 测试环境&am…...

【C++】——精细化哈希表架构:理论与实践的综合分析
先找出你的能力在哪里,然后再决定你是谁。 —— 塔拉韦斯特弗 《你当像鸟飞往你的山》 目录 1. C 与哈希表:核心概念与引入 2. 哈希表的底层机制:原理与挑战 2.1 核心功能解析:效率与灵活性的平衡 2.2 哈希冲突的本质&#x…...

【cocos creator】拖拽排序列表
DEMO下载 GameCtrl.ts import ItemCtrl from "./ItemCtrl";const { ccclass, property } cc._decorator;ccclass export default class GameCtrl extends cc.Component {property(cc.Node)content: cc.Node null;property(cc.Node)prefab: cc.Node null;arr []…...

b站——《【强化学习】一小时完全入门》学习笔记及代码(1-3 多臂老虎机)
问题陈述 我们有两个多臂老虎机(Multi-Armed Bandit),分别称为左边的老虎机和右边的老虎机。每个老虎机的奖励服从不同的正态分布: 左边的老虎机:奖励服从均值为 500,标准差为 50 的正态分布,即…...

【Mac排错】ls: command not found 终端命令失效的解决办法
【TroubleShooting on Mac】ls: command not found 终端命令失效的解决办法 A Solution to Solve “Command not found” of Terminal on Mac 一直在使用心爱的MacBook Pro的Terminal,并且为她定制了不同的Profile。 这样,看起来她可以在不同季节&…...
探秘Hugging Face与DeepSeek:AI开源世界的闪耀双子星
目录 一、引言:AI 开源浪潮的澎湃二、Hugging Face:AI 开源社区的基石(一)起源与发展历程(二)核心技术与特色(三)在 AI 领域的广泛应用 三、DeepSeek:东方崛起的 AI 新势…...

SkyWalking 10.1.0 实战:从零构建全链路监控,解锁微服务性能优化新境界
文章目录 前言一、集成SkyWalking二、SkyWalking使用三、SkyWalking性能剖析四、SkyWalking 告警推送4.1 配置告警规则4.2 配置告警通知地址4.3 下发告警信息4.4 测试告警4.5 慢SQL查询 总结 前言 在传统监控系统中,我们通过进程监控和日志分析来发现系统问题&…...

本地部署DeepSeek-R1(Mac版)
本地部署DeepSeek-R1(Mac版) 前言:过年这段时间,DeepSeek火遍全球,但遭受黑客攻击,10次对话基本9次都是服务器繁忙,请稍后重试。那么,本地部署整起来 总体来说,本地部署…...

网易易盾接入DeepSeek,数字内容安全“智”理能力全面升级
今年农历新年期间,全球AI领域再度掀起了一波革命性浪潮,国产通用大模型DeepSeek凭借其强大的多场景理解与内容生成能力迅速“出圈”,彻底改写全球人工智能产业的格局。 作为国内领先的数字内容风控服务商,网易易盾一直致力于探索…...

apachePoi中XSSFClientAnchor图片坐标简述;填充多张图片
概述 业务中经常会遇到在单元格内填充图片的需求,而且要求指定图片在单元格内的位置。 一般都是用的apache的poi,设置图片坐标。 HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2)dx1 dy1 起始单元…...
Java、Go、Rust、Node.js 的内存占比及优缺点分析
在选择编程语言进行项目开发时,内存占用是一个重要的考量因素。不同语言在内存管理、垃圾回收、并发模型等方面各有特点,影响着它们的内存使用情况。本文将对 Java、Go、Rust 和 Node.js 的内存占比进行对比,并分析它们的优缺点。 1. Java 的…...
C++智能指针的使用
文章目录 智能指针的使用和原理智能指针的使用场景RAII和智能指针C标准库智能指针的使用 智能指针的使用和原理 智能指针的使用场景 1. 下面的程序中,new了以后,我们也delete了,但是因为抛异常导致后面的delete没有得到执行,所以…...
计算机毕业设计——Springboot的社区维修平台旅游管理
📘 博主小档案: 花花,一名来自世界500强的资深程序猿,毕业于国内知名985高校。 🔧 技术专长: 花花在深度学习任务中展现出卓越的能力,包括但不限于java、python等技术。近年来,花花更…...
MySQL ALTER 命令详解
MySQL ALTER 命令详解 引言 MySQL 是一款广泛使用的开源关系数据库管理系统,ALTER 命令在 MySQL 数据库管理中扮演着至关重要的角色。ALTER 命令用于修改现有的数据库、表或列的定义。本文将详细介绍 MySQL ALTER 命令的用法、功能及其在实际应用中的重要性。 ALTER 命令概…...

02、QLExpress从入门到放弃,相关API和文档
QLExpress从入门到放弃,相关API和文档 一、属性开关 public class ExpressRunner {private boolean isTrace;private boolean isShortCircuit;private boolean isPrecise; }/*** 是否需要高精度计算*/ private boolean isPrecise false;高精度计算在会计财务中非常重要&…...

Mp4视频播放机无法播放视频-批量修改视频分辨率(帧宽、帧高)
背景 家人有一台夏新多功能 视频播放器(夏新多功能 视频播放器),用来播放广场舞。下载了一些广场舞视频, 只有部分视频可以播放,其他视频均无法播放,判断应该不是帧速率和数据速率的限制, 分析可能是播放器不支持帧高度大于720的视频。由于视频文件较多,需要借助视频编…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...

如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...