flutter 截图和保存图片到本地和相册,并做分享

1,400 阅读2分钟

参考自:flutter 截图和保存图片到本地和相册,并做分享

第一步:注册全局的key与RepaintBoundary匹配,来标明截图内容。

//全局key-截图key
final GlobalKey repaintWidgetKey = GlobalKey();

第二步:将需要截图的widget包裹在RepaintBoundary组件中,加入key属性。

RepaintBoundary(
  key: repaintWidgetKey,
  child: Container(
    padding: const EdgeInsets.only(left: 15, right: 15),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Expanded(
          child: WebViewWidget(
              controller: WebViewController()
                ..setJavaScriptMode(JavaScriptMode.unrestricted)
                ..loadHtmlString(HtmlUtils.getHtmlData(newDetailsEntity.content.toString(), 14))),
        ),
        SizedBox(
          height: 50,
          child: Row(
            children: [
              Expanded(
                child: InkWell(
                  onTap: (){
                    RepaintBoundaryUtils().savePhoto(repaintWidgetKey);
                  },
                  child: RichText(
                    textAlign: TextAlign.center,
                    text:const TextSpan(
                        children: [
                          TextSpan(
                              text: "保存 ",
                              style: TextStyle(fontSize: 14,color: Colors.black)
                          ),
                          WidgetSpan(child: LoadAssetImage("home/img_zhuanfa",width: 18,height: 18)),
                        ]
                    ),
                  ),
                )
              )
            ],
          ),
        )
      ],
    ),
  ),
)

第三步:调用保存封装类方法

RepaintBoundaryUtils().savePhoto(repaintWidgetKey);

第四步:封装类代码

import 'dart:io';
import 'dart:typed_data';
import 'dart:async';
import 'dart:ui';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:oktoast/oktoast.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

//全局key-截图key
late GlobalKey boundaryKey;

class RepaintBoundaryUtils {
//生成截图
  /// 截屏图片生成图片流ByteData
  Future<String> captureImage() async {
    RenderRepaintBoundary? boundary = boundaryKey.currentContext!
        .findRenderObject() as RenderRepaintBoundary?;
    double dpr = ui.window.devicePixelRatio; // 获取当前设备的像素比
    var image = await boundary!.toImage(pixelRatio: dpr);
    // 将image转化成byte
    ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);

    var filePath = "";

    Uint8List pngBytes = byteData!.buffer.asUint8List();
    // 获取手机存储(getTemporaryDirectory临时存储路径)
    Directory applicationDir = await getTemporaryDirectory();
    // getApplicationDocumentsDirectory();
    // 判断路径是否存在
    bool isDirExist = await Directory(applicationDir.path).exists();
    if (!isDirExist) Directory(applicationDir.path).create();
    // 直接保存,返回的就是保存后的文件
    File saveFile = await File(
        "${applicationDir.path}${DateTime.now().toIso8601String()}.jpg")
        .writeAsBytes(pngBytes);
    filePath = saveFile.path;
    // if (Platform.isAndroid) {
    //   // 如果是Android 的话,直接使用image_gallery_saver就可以了
    //   // 图片byte数据转化unit8
    //   Uint8List images = byteData!.buffer.asUint8List();
    //   // 调用image_gallery_saver的saveImages方法,返回值就是图片保存后的路径
    //   String result = await ImageGallerySaver.saveImage(images);
    //   // 需要去除掉file://开头。生成要使用的file
    //   File saveFile = new File(result.replaceAll("file://", ""));
    //   filePath = saveFile.path;
    //
    //
    // } else if (Platform.isIOS) {
    //   // 图片byte数据转化unit8
    //
    // }

    return filePath;
  }

//申请存本地相册权限
  Future<bool> getPormiation() async {
    if (Platform.isIOS) {
      var status = await Permission.photos.status;
      if (status.isDenied) {
        Map<Permission, PermissionStatus> statuses = await [
          Permission.photos,
        ].request();
        // saveImage(globalKey);
      }
      return status.isGranted;
    } else {
      var status = await Permission.storage.status;
      if (status.isDenied) {
        Map<Permission, PermissionStatus> statuses = await [
          Permission.storage,
        ].request();
      }
      return status.isGranted;
    }
  }

//保存到相册
  void savePhoto(GlobalKey repaintWidgetKey) async {
    boundaryKey=repaintWidgetKey;
    RenderRepaintBoundary? boundary = boundaryKey.currentContext!
        .findRenderObject() as RenderRepaintBoundary?;

    double dpr = ui.window.devicePixelRatio; // 获取当前设备的像素比
    var image = await boundary!.toImage(pixelRatio: dpr);
    // 将image转化成byte
    ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
    //获取保存相册权限,如果没有,则申请改权限
    bool permition = await getPormiation();

    var status = await Permission.photos.status;
    if (permition) {
      if (Platform.isIOS) {
        if (status.isGranted) {
          Uint8List images = byteData!.buffer.asUint8List();
          final result = await ImageGallerySaver.saveImage(images,
              quality: 60, name: "hello");
          showToast("保存成功");
        }
        if (status.isDenied) {
          print("IOS拒绝");
        }
      } else {
        //安卓
        if (status.isGranted) {
          print("Android已授权");
          Uint8List images = byteData!.buffer.asUint8List();
          final result = await ImageGallerySaver.saveImage(images, quality: 60);
          if (result != null) {
            showToast("保存成功");
          } else {
            print('error');
            // toast("保存失败");
          }
        }
      }
    }else{
      //重新请求--第一次请求权限时,保存方法不会走,需要重新调一次
      savePhoto(boundaryKey);
    }
  }
}

说明:以下是用到的插件

#保存图片到相册
image_gallery_saver: ^2.0.3
#权限管理
permission_handler: ^8.1.6
#获取临时路径
path_provider: ^2.1.1