Flutter:邀请海报,Widget转图片,保存相册

记录下,把页面红色区域内的内容,转成图片后保存到相册的功能

依赖

js 复制代码
# 生成二维码
qr_flutter: ^4.1.0
# 保存图片
image_gallery_saver_plus: ^3.0.5

view

js 复制代码
import 'package:demo/common/index.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';

import 'index.dart';

class SharePage extends GetView<ShareController> {
  const SharePage({super.key});

  // 主视图
  Widget _buildView() {
    return RepaintBoundary(
      key: controller.qrKey,
      child: <Widget>[
        TDImage(
          assetUrl: 'assets/img/user.png',
          width: 100.w,
          height: 100.w,
        ),
        TextWidget.body('邀请码:10086', size: 40.sp),
        QrImageView(
          data: '10086',
          version: QrVersions.auto,
          size: 400.w,
          gapless: false,
          embeddedImage: const AssetImage('assets/img/user.png'),
          embeddedImageStyle: QrEmbeddedImageStyle(
            size: Size(100.w, 100.w),
          ),
        ),
      ].toColumn(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
      ).card(color: Colors.white).tight(width: 750.w, height: 750.w),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GetBuilder<ShareController>(
      init: ShareController(),
      id: "share",
      builder: (_) {
        return Scaffold(
          backgroundColor: const Color(0xffF5F6FA),
          appBar: TDNavBar(
            height: 45,
            title: '邀请码',
            titleFontWeight: FontWeight.w600,
            backgroundColor: Colors.white,
            screenAdaptation: true,
            useDefaultBack: true,
            rightBarItems: [
              TDNavBarItem(
                iconWidget: Text('保存'),
                action: controller.saveQrCode,
              ),
            ],
          ),
          body: SafeArea(
            child: _buildView(),
          ),
        );
      },
    );
  }
}

controller

js 复制代码
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart';
import 'package:image_gallery_saver_plus/image_gallery_saver_plus.dart';

class ShareController extends GetxController {
  final GlobalKey qrKey = GlobalKey();
  
  Future<void> saveQrCode() async {
    try {
      // 获取 RenderRepaintBoundary
      final boundary = qrKey.currentContext!
          .findRenderObject() as RenderRepaintBoundary;
      
      // 等待一下确保UI已经完全渲染
      await Future.delayed(const Duration(milliseconds: 20));
      
      // 将 Widget 转换成图片
      final image = await boundary.toImage(pixelRatio: 3.0);
      
      // 将图片转换成字节数据
      final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
      
      if (byteData != null) {
        // 使用 image_gallery_saver_plus 保存到相册
        final result = await ImageGallerySaverPlus.saveImage(
          byteData.buffer.asUint8List(),
          quality: 100,
          name: "qr_code_${DateTime.now().millisecondsSinceEpoch}"
        );
        
        if (result != null && result['isSuccess']) {
          Get.snackbar('提示', '保存成功');
        } else {
          Get.snackbar('提示', '保存失败,请确保已授予存储权限');
        }
      }
    } catch (e) {
      print('保存失败:$e');
      Get.snackbar('提示', '保存失败,请确保已授予存储权限');
    }
  }
}

AndroidManifest.xml 权限配置

js 复制代码
<!-- 允许应用写入外部存储 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 允许应用读取外部存储 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 允许应用读取媒体图像 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<application
	android:requestLegacyExternalStorage="true">
相关推荐
恋猫de小郭27 分钟前
Android CLI 支持 AI Agent 通过 Device Streaming 调试云真机
android·前端·flutter
m0_7381858217 小时前
Flutter 鸿蒙化实战:flutter_scankit 适配 OpenHarmony,华为 ScanKit 扫码
flutter·华为·harmonyos·鸿蒙
事圆则缓1 天前
Flutter 开发鸿蒙实战:从 OpenHarmony 适配版到 HAP 构建与插件接入
flutter·华为·harmonyos
天空之城--1 天前
Android一周动态:Android 18首次官宣、Compose Material3 1.4转正(5趋势+5资讯)
android·人工智能·flutter·架构·android jetpack
恋猫de小郭1 天前
Meta 分享怎么用 AI 迁移 Compose 项目不烧心
android·前端·flutter
EatFan1 天前
Flutter 鸿蒙适配实践 2026:从环境搭建、混合渲染到 OpenTelemetry 性能基建
flutter·华为·harmonyos·openharmony·opentelemetry·鸿蒙适配·impeller
m0_738185821 天前
Flutter 鸿蒙化实战:flutter_secure_storage 适配 OpenHarmony,敏感数据安全存储
安全·flutter·华为·harmonyos·鸿蒙
传奇开心果编程2 天前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
m0_738185822 天前
Flutter 鸿蒙化实战:flutter_nfc_kit 适配 OpenHarmony,NFC 读写一步到位
flutter·华为·harmonyos·鸿蒙
恋猫de小郭2 天前
KMP 又改了编译流程, Separate Compilation 禁止了 `commonMain` 的依赖穿透
android·前端·flutter