Flutter画中画功能插件fl_pip的使用

发布于 1周前 作者 phonegap100 来自 Flutter

Flutter画中画功能插件fl_pip的使用

简介

fl_pip 是一个用于Flutter应用的插件,它允许开发者在iOS和Android平台上实现画中画(PiP, Picture-in-Picture)模式。通过这个插件,你可以显示Flutter的view,并且可以通过修改Flutter栈顶的view来展示任意UI。

然而,在iOS上存在一个问题:当应用处于后台时,Flutter UI可能会停止运行或直接黑屏。这可能是由于iOS冻结了应用程序导致的。目前还没有完美的解决方案,如果你有好的想法,请提交PR。

使用配置

iOS 配置

  1. Signing & Capabilities -> Capability 中添加 BackgroundModes
  2. 勾选 Audio, AirPlay, And Picture in Picture
  3. 修改 /ios/Runner/AppDelegate.swift 文件的内容如下:
import fl_pip
import Flutter
import UIKit

@main
@objc class AppDelegate: FlFlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

    override func registerPlugin(_ registry: FlutterPluginRegistry) {
        GeneratedPluginRegistrant.register(with: registry)
    }
}

Android 配置

  1. 修改 android/app/src/main/${your package name}/MainActivity 继承 FlPiPActivity
  2. AndroidManifest.xml 文件中添加 android:supportsPictureInPicture="true" 属性。
<application android:label="FlPiP">
    <activity android:name=".MainActivity" 
              android:launchMode="singleTop" 
              android:supportsPictureInPicture="true" />
</application>

Kotlin 示例代码

class MainActivity : FlPiPActivity()

Java 示例代码

class MainActivity extends FlPiPActivity {

}

方法列表

以下是 fl_pip 插件提供的主要方法:

  • enable(): 开启画中画模式。

    void enable() {
      FlPiP().enable(
          iosConfig: FlPiPiOSConfig(),
          androidConfig: FlPiPAndroidConfig(
              aspectRatio: const Rational.maxLandscape()));
    }
    
  • isAvailable(): 检查是否支持画中画模式。

    bool isAvailable = await FlPiP().isAvailable;
    
  • isActive(): 获取当前画中画窗口的状态。

    bool isActive = await FlPiP().isActive;
    
  • toggle(): 切换前后台(仅iOS支持切换到后台)。

    void toggle() {
      FlPiP().toggle();
    }
    
  • disable(): 退出画中画模式。

    void disable() {
      FlPiP().disable();
    }
    

示例代码

下面是一个完整的示例代码,展示了如何使用 fl_pip 插件创建一个带有计时器的应用程序,并启用画中画模式。

import 'package:flutter/material.dart';
import 'package:flutter_waya/flutter_waya.dart'; // Assuming this is a custom package for widgets like CountDown

void main() {
  runApp(App(home: HomePage()));
}

/// mainName must be the same as the method name
@pragma('vm:entry-point')
void pipMain() {
  runApp(ClipRRect(
      borderRadius: BorderRadius.circular(12),
      child: App(home: PiPHomePage())));
}

class App extends StatelessWidget {
  const App({super.key, required this.home});

  final Widget home;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        home: home);
  }
}

class Timer extends StatelessWidget {
  const Timer({super.key});

  @override
  Widget build(BuildContext context) => CountDown(
      duration: const Duration(seconds: 500),
      builder: (Duration duration, bool isRunning, VoidCallback startTiming) {
        return Padding(
            padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 12),
            child: Text('timer:${duration.inSeconds.toString()}'));
      });
}

class Filled extends StatelessWidget {
  const Filled({super.key, required this.text, this.onPressed});

  final String text;
  final VoidCallback? onPressed;

  @override
  Widget build(BuildContext context) {
    return FilledButton(
        onPressed: onPressed, child: Text(text, textAlign: TextAlign.center));
  }
}

// Example pages
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Home Page")),
      body: Center(child: Text("This is the Home Page")),
    );
  }
}

class PiPHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("PiP Home Page")),
      body: Center(child: Timer()),
    );
  }
}

在这个示例中:

  • pipMain 函数是必须的,如果使用 enableWithEngine 方法。
  • Timer 小部件展示了如何在画中画模式下显示一个倒计时。
  • HomePagePiPHomePage 分别代表主页面和进入画中画模式后的页面。

希望这些信息能帮助你更好地理解和使用 fl_pip 插件。如果你有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter画中画功能插件fl_pip的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter画中画功能插件fl_pip的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现画中画(Picture-in-Picture,PiP)功能,你可以使用fl_pip插件。这个插件可以帮助你在Android和iOS平台上实现画中画模式。以下是一个简单的示例,展示了如何使用fl_pip插件在Flutter应用中实现画中画功能。

首先,确保你已经将fl_pip插件添加到你的Flutter项目中。你可以在pubspec.yaml文件中添加以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  fl_pip: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,是具体的代码实现。在这个例子中,我们将创建一个简单的Flutter应用,该应用包含一个视频播放器,并允许用户将视频播放切换到画中画模式。

1. 主应用代码(main.dart

import 'package:flutter/material.dart';
import 'package:fl_pip/fl_pip.dart';
import 'package:chewie/chewie.dart'; // 用于视频播放的插件,可以替换为你喜欢的视频播放器

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter PiP Example'),
        ),
        body: Center(
          child: PipProvider(
            child: VideoPlayerScreen(),
          ),
        ),
      ),
    );
  }
}

class VideoPlayerScreen extends StatefulWidget {
  @override
  _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}

class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  ChewieController? _chewieController;

  @override
  void initState() {
    super.initState();
    _chewieController = ChewieController(
      source: ChewieSource(
        mediaItem: MediaItem.network(
          'https://www.w3schools.com/html/mov_bbb.mp4', // 替换为你的视频URL
          mediaType: MediaType.video,
        ),
        autoplay: true,
        looping: true,
      ),
      aspectRatio: ChewieAspectRatio.preserve,
      autoPlay: true,
      showControls: true,
      materialProgressColors: ProgressColors(
        playedColor: Colors.red,
        handleColor: Colors.blue,
        bufferedColor: Colors.grey.shade300,
      ),
      // 其他ChewieController配置...
    );
  }

  @override
  Widget build(BuildContext context) {
    return PipConsumer(
      builder: (context, pipController) {
        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Expanded(
              child: Chewie(
                controller: _chewieController!,
                onEnterPictureInPicture: () {
                  pipController.enterPictureInPicture();
                },
              ),
            ),
            ElevatedButton(
              onPressed: () {
                pipController.enterPictureInPicture();
              },
              child: Text('Enter PiP Mode'),
            ),
          ],
        );
      },
    );
  }

  @override
  void dispose() {
    _chewieController?.dispose();
    super.dispose();
  }
}

2. 配置Android权限(AndroidManifest.xml

在你的AndroidManifest.xml文件中,确保添加了必要的权限以支持画中画模式:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <application
        ... >
        <activity
            ...
            android:supportsPictureInPicture="true"
            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
            ...
        </activity>
    </application>
</manifest>

3. iOS配置(Info.plist

对于iOS,你需要确保你的Info.plist文件中有适当的配置来支持画中画模式。通常,这不需要额外的键,但你需要确保你的应用支持后台音频播放,因为画中画通常伴随着音频播放。

注意事项

  • 在实际项目中,你可能需要处理更多的状态管理和错误处理。
  • 画中画模式在不同设备和操作系统版本上的行为可能有所不同,因此请务必进行充分的测试。
  • 确保你的视频播放器插件支持画中画功能,或者根据需要进行自定义。

这个示例应该能帮助你快速上手在Flutter中使用fl_pip插件实现画中画功能。

回到顶部