Flutter原生截图功能插件ff_native_screenshot的使用

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

Flutter原生截图功能插件ff_native_screenshot的使用

插件简介

ff_native_screenshot 是一个Flutter插件,允许开发者在Android和iOS平台上截取或监听屏幕截图(支持平台视图)。它是针对RepaintBoundary无法截取平台视图的截图问题的一个解决方案。

pub package GitHub stars GitHub forks GitHub license GitHub issues

使用方法

添加依赖

pubspec.yaml文件中添加以下依赖:

dependencies:
  ff_native_screenshot: any
  # only for android
  permission_handler: any

截取屏幕截图

通过调用FfNativeScreenshot().takeScreenshot()来获取屏幕截图的数据。例如:

Uint8List? data = await FfNativeScreenshot().takeScreenshot();

监听屏幕截图

如果需要监听屏幕截图事件,可以按照下面的方式设置:

@override
void initState() {
  super.initState();
  init();
}

Future<void> init() async {
  if (Platform.isAndroid) {
    await Permission.storage.request();
  }
  FfNativeScreenshot().setup(ScreenshotFlutterApiImplements(context));
  await FfNativeScreenshot().startListeningScreenshot();

  if (mounted) {
    setState(() {});
  }
}

@Override
void dispose() {
  FfNativeScreenshot().stopListeningScreenshot();
  super.dispose();
}

bool? listening;
@Override
void didChangeAppLifecycleState(AppLifecycleState state) {
  super.didChangeAppLifecycleState(state);
  switch (state) {
    case AppLifecycleState.resumed:
      if (listening == true && !FfNativeScreenshot().listening) {
        FfNativeScreenshot().startListeningScreenshot();
      }
      break;
    case AppLifecycleState.paused:
      listening = FfNativeScreenshot().listening;
      if (listening == true) {
        FfNativeScreenshot().stopListeningScreenshot();
      }

      break;
    default:
  }
}

class ScreenshotFlutterApiImplements extends ScreenshotFlutterApi {
  ScreenshotFlutterApiImplements(this.context);
  final BuildContext context;
  @override
  Future<void> onTakeScreenshot(Uint8List? data) async {
    // 如果有错误发生
    // 您可以调用 takeScreenshot 
    data ??= await FfNativeScreenshot().takeScreenshot();
  }
}

示例代码

下面是完整的示例代码,演示如何使用ff_native_screenshot插件创建一个能够截取屏幕截图的应用程序。

import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:ff_native_screenshot/ff_native_screenshot.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:webview_flutter/webview_flutter.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    init();
    WidgetsBinding.instance.addObserver(this);
  }

  Future<void> init() async {
    if (Platform.isAndroid) {
      await Permission.storage.request();
    }
    FfNativeScreenshot().setup(ScreenshotFlutterApiImplements(context));
    await FfNativeScreenshot().startListeningScreenshot();

    if (mounted) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    FfNativeScreenshot().stopListeningScreenshot();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  bool? listening;
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    switch (state) {
      case AppLifecycleState.resumed:
        if (listening == true && !FfNativeScreenshot().listening) {
          FfNativeScreenshot().startListeningScreenshot();
        }
        break;
      case AppLifecycleState.paused:
        listening = FfNativeScreenshot().listening;
        if (listening == true) {
          FfNativeScreenshot().stopListeningScreenshot();
        }

        break;
      default:
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Native Screenshot'),
        actions: <Widget>[
          IconButton(
            onPressed: () {
              takeScreenshot(context);
            },
            icon: const Icon(Icons.screenshot),
          ),
          IconButton(
              onPressed: () {
                _listeningScreenshotTapped();
              },
              icon: FfNativeScreenshot().listening
                  ? const Icon(Icons.stop)
                  : const Icon(Icons.start))
        ],
      ),
      body: WebView(
        initialUrl: 'https://flutter.cn',
        backgroundColor: Platform.isAndroid ? Colors.white.withOpacity(0.99) : null,
      ),
    );
  }

  Future<void> _listeningScreenshotTapped() async {
    if (FfNativeScreenshot().listening) {
      await FfNativeScreenshot().stopListeningScreenshot();
    } else {
      await FfNativeScreenshot().startListeningScreenshot();
    }
    if (mounted) {
      setState(() {});
    }
  }

  Future<void> takeScreenshot(BuildContext context) async {
    Uint8List? data = await FfNativeScreenshot().takeScreenshot();
    showScreenshotDialog(data, context);
  }

  static void showScreenshotDialog(Uint8List? bytes, BuildContext context) {
    if (bytes != null) {
      showDialog(
        context: context,
        builder: (context) {
          return GestureDetector(
            behavior: HitTestBehavior.translucent,
            onTap: () {
              Navigator.of(context).pop();
            },
            child: Padding(
              padding: const EdgeInsets.all(50),
              child: Image.memory(
                bytes,
                fit: BoxFit.contain,
              ),
            ),
          );
        },
      );
    }
  }
}

class ScreenshotFlutterApiImplements extends ScreenshotFlutterApi {
  ScreenshotFlutterApiImplements(this.context);
  final BuildContext context;
  @override
  Future<void> onTakeScreenshot(Uint8List? data) async {
    if (kDebugMode) {
      print('onTakeScreenshot:${data?.length}');
    }
    data ??= await FfNativeScreenshot().takeScreenshot();
    _HomePageState.showScreenshotDialog(data, context);
  }
}

此示例展示了如何创建一个简单的Flutter应用程序,该应用程序具有截屏和监听截屏的功能,并将截取的图片显示在一个对话框中。


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

1 回复

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


当然,下面是一个关于如何在Flutter项目中使用ff_native_screenshot插件来实现原生截图功能的代码示例。

首先,你需要在pubspec.yaml文件中添加ff_native_screenshot依赖:

dependencies:
  flutter:
    sdk: flutter
  ff_native_screenshot: ^latest_version  # 请替换为最新版本号

然后运行flutter pub get来获取依赖。

接下来,在你的Flutter项目中使用这个插件。以下是一个简单的示例,展示了如何捕获屏幕截图并将其保存到设备相册:

import 'package:flutter/material.dart';
import 'package:ff_native_screenshot/ff_native_screenshot.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ScreenshotPage(),
    );
  }
}

class ScreenshotPage extends StatefulWidget {
  @override
  _ScreenshotPageState createState() => _ScreenshotPageState();
}

class _ScreenshotPageState extends State<ScreenshotPage> {
  final GlobalKey _globalKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('FF Native Screenshot Example'),
      ),
      body: Container(
        key: _globalKey,
        alignment: Alignment.center,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Hello, Flutter!',
              style: TextStyle(fontSize: 24),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                try {
                  // 捕获截图
                  final ScreenshotController screenshotController = ScreenshotController();
                  final Uint8List pngBytes = await screenshotController.captureFromWidget(
                    context,
                    _globalKey.currentContext,
                  );

                  // 将截图保存到相册
                  bool result = await FFNativeScreenshot.saveImageToGallery(pngBytes);
                  if (result) {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Screenshot saved to gallery!')),
                    );
                  } else {
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(content: Text('Failed to save screenshot.')),
                    );
                  }
                } catch (e) {
                  print('Error capturing screenshot: $e');
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Error capturing screenshot.')),
                  );
                }
              },
              child: Text('Capture Screenshot'),
            ),
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮。当用户点击按钮时,会捕获当前页面的截图并将其保存到设备的相册中。

请注意以下几点:

  1. 我们使用GlobalKey来指定需要截图的Widget。
  2. 使用ScreenshotControllercaptureFromWidget方法来捕获截图。
  3. 使用FFNativeScreenshot.saveImageToGallery方法将截图保存到相册。

确保在Android和iOS项目中分别配置好必要的权限,以便能够访问设备相册。在Android中,你可能需要在AndroidManifest.xml文件中添加WRITE_EXTERNAL_STORAGE权限。在iOS中,你可能需要在Info.plist中添加NSPhotoLibraryAddUsageDescription权限描述。

希望这个示例对你有所帮助!

回到顶部