2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Flutter实现绘制芬香小程序二维码海报 并保存到相册

Flutter实现绘制芬香小程序二维码海报 并保存到相册

时间:2022-08-08 08:55:56

相关推荐

Flutter实现绘制芬香小程序二维码海报 并保存到相册

效果展示

准备工作

引入依赖插件

qr_flutter: ^3.0.1cached_network_image: ^1.0.0

导入图片处理包

import 'dart:ui' as ui;

实现代码

入口文件 share_content_post.dart

class ShareContentPost extends StatefulWidget {String bgUrl;String qrImageUrl;ShareContentPost({this.bgUrl, this.qrImageUrl});@override_ShareContentPostState createState() => _ShareContentPostState();}class _ShareContentPostState extends State<ShareContentPost> {GlobalKey globalKey = GlobalKey();Future<void> _capturePng() async {// '保存中...'RenderRepaintBoundary boundary =globalKey.currentContext.findRenderObject();ui.Image image =await boundary.toImage(pixelRatio: window.devicePixelRatio);ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);Uint8List pngBytes = byteData.buffer.asUint8List();print(pngBytes);var filePath = await ImagePickerSaver.saveFile(fileData: pngBytes);var savedFile = File.fromUri(Uri.file(filePath));setState(() {Future<File>.sync(() => savedFile);});// '保存成功'NavigatorUtil.goBack(context);}@overrideWidget build(BuildContext context) {return Scaffold(appBar: MyAppBar(centerTitle: "生成海报",actionName: "保存到相册",onPressed: () {_capturePng();},),body: Center(child: Container(height: 1334 * 0.4,width: 750 * 0.4,child: RepaintBoundary(key: globalKey,child: EnterPostPage(bgUrl: widget.bgUrl,qrImageUrl: widget.qrImageUrl),),),),);}}

绘制组件 post_enter.dart

enum Status { loading, complete }class MainPainter extends CustomPainter {final Background background;final MainQR hero;final PostAvatar postAvatar;final Size size;final String url;MainPainter({this.background, this.hero, this.url, this.size, this.postAvatar});@overridevoid paint(Canvas canvas, Size size) {background.paint(canvas, size);postAvatar.paint(canvas, size);hero.paint(canvas, size);}@overridebool shouldRepaint(CustomPainter oldDelegate) {// TODO: implement shouldRepaintreturn oldDelegate != this;}}class EnterPostPage extends StatefulWidget {String bgUrl;String qrImageUrl;EnterPostPage({this.bgUrl, this.qrImageUrl});_EnterPostPage createState() => _EnterPostPage();}class _EnterPostPage extends State<EnterPostPage>with TickerProviderStateMixin {Status gameStatus = Status.loading;int index = 0;Background background;MainQR hero;PostAvatar postAvatar;initState() {initPost();}Widget build(BuildContext context) {if (gameStatus == Status.loading) {return ColorLoader();}return CustomPaint(painter: MainPainter(background: background,hero: hero,postAvatar: postAvatar,size: Size(750, 1334)),size: Size(750, 1334));}void initPost() async {background = new Background(url: widget.bgUrl);hero = new MainQR(url: widget.qrImageUrl);postAvatar = new PostAvatar();await hero.init();await postAvatar.init();await background.init();setState(() {gameStatus = plete;});}}

背景组件 post_bg.dart

// 背景图class Background {// 屏幕的宽度double screenWidth = 750;// 屏幕的高度double screenHeight = 1334;// 加载的背景图片ui.Image image;String url;// 构造函数Background({this.url});// 初始化, 各种资源Future<VoidCallback> init() async {image = await Utils.loadImageByProvider(CachedNetworkImageProvider(url));}// 绘图函数paint(Canvas canvas, Size size) async {Rect screenWrap =Offset(0.0, 0.0) & Size(screenWidth * 0.4, screenHeight * 0.4);Paint screenWrapPainter = new Paint();screenWrapPainter.color = Colors.red;screenWrapPainter.style = PaintingStyle.fill;canvas.drawRect(screenWrap, screenWrapPainter);canvas.save();canvas.scale(0.4, 0.4);Paint paint = new Paint();canvas.drawImageRect(image,Offset(0.0, 0.0) &Size(image.width.toDouble(), image.height.toDouble()),Offset(0.0, 0.0) & Size(screenWidth, screenHeight),paint);canvas.restore();}}

头像昵称文字绘制组件

class PostAvatar {ui.Image image;String nickName;PostAvatar();@overridevoid init() async {User user = UserManager.currentUser;var avatarUrl = user.avatarUrl;nickName = user.nickName;image =await Utils.loadImageByProvider(CachedNetworkImageProvider(avatarUrl));}@overridevoid paint(Canvas canvas, Size size) {canvas.save();Paint paint = new Paint();canvas.scale(0.35, 0.35);print(image.width);var textLeft = 180.0;ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle(textAlign: TextAlign.left,fontSize: 36.0,textDirection: TextDirection.ltr,maxLines: 1,),)..pushStyle(ui.TextStyle(color: Colours.text_black_333,textBaseline: ui.TextBaseline.alphabetic),)..addText(nickName);ui.Paragraph paragraph = paragraphBuilder.build()..layout(ui.ParagraphConstraints(width: 500.0));canvas.drawParagraph(paragraph, Offset(textLeft, 1350.0));ui.ParagraphBuilder paragraphBuilder2 = ui.ParagraphBuilder(ui.ParagraphStyle(textAlign: TextAlign.left,fontSize: 36.0,textDirection: TextDirection.ltr,maxLines: 1,),)..pushStyle(ui.TextStyle(color: Colours.text_black_999,textBaseline: ui.TextBaseline.alphabetic),)..addText('邀您一起加入芬香社交电商');ui.Paragraph paragraph2 = paragraphBuilder2.build()..layout(ui.ParagraphConstraints(width: 500.0));canvas.drawParagraph(paragraph2, Offset(textLeft, 1390.0));ui.ParagraphBuilder paragraphBuilder3 = ui.ParagraphBuilder(ui.ParagraphStyle(textAlign: TextAlign.left,fontSize: 32.0,textDirection: TextDirection.ltr,maxLines: 1,),)..pushStyle(ui.TextStyle(color: Colours.text_black_999,textBaseline: ui.TextBaseline.alphabetic),)..addText('京东社交电商战略合作伙伴');ui.Paragraph paragraph3 = paragraphBuilder3.build()..layout(ui.ParagraphConstraints(width: 500.0));canvas.drawParagraph(paragraph3, Offset(textLeft, 1430.0));var radius = image.width.toDouble() / 2;var top = 1350.0;var left = 30.0;canvas.clipRRect(RRect.fromRectXY(Rect.fromLTWH(left, top, image.width.toDouble(), image.width.toDouble()),radius,radius),doAntiAlias: false);canvas.drawImageRect(image, Offset(0.0, 0.0) & Size(400, 400),Offset(left, top) & Size(400.0, 400.0), paint);canvas.restore();}}

二维码绘制组件

class MainQR {ui.Image image;String url;MainQR({this.url});@overridevoid init() async {image = await Utils.loadImageByProvider(CachedNetworkImageProvider(url));}@overridevoid paint(Canvas canvas, Size size) {canvas.save();Paint paint = new Paint();canvas.scale(0.25, 0.25);canvas.drawImageRect(image, Offset(0.0, 0.0) & Size(400, 400),Offset(850.0, 1770.0) & Size(400.0, 400.0), paint);ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle(textAlign: TextAlign.center,fontSize: 36.0,textDirection: TextDirection.ltr,maxLines: 1,),)..pushStyle(ui.TextStyle(color: Colours.text_black_999,textBaseline: ui.TextBaseline.alphabetic),)..addText("长按识别");ui.Paragraph paragraph = paragraphBuilder.build()..layout(ui.ParagraphConstraints(width: 200.0));canvas.drawParagraph(paragraph, Offset(885.0, 2050.0));canvas.restore();}}

用到的图片转换工具方法

static Future<ui.Image> getImage(String asset) async {ByteData data = await rootBundle.load(asset);var codec = await ui.instantiateImageCodec(data.buffer.asUint8List());FrameInfo fi = await codec.getNextFrame();return fi.image;}static Future<ui.Image> getImageByQR(String url, {size: 70.0}) async {final image = await QrPainter(data: url,version: QrVersions.auto,gapless: false,).toImage(size);final a = await image.toByteData(format: ImageByteFormat.png);var codec = await ui.instantiateImageCodec(a.buffer.asUint8List());FrameInfo fi = await codec.getNextFrame();return fi.image;}static Future<ui.Image> loadImageByProvider(ImageProvider provider, {ImageConfiguration config = ImageConfiguration.empty,}) async {Completer<ui.Image> completer = Completer<ui.Image>(); //完成的回调ImageStreamListener listener;ImageStream stream = provider.resolve(config); //获取图片流listener = ImageStreamListener((ImageInfo frame, bool sync) {//监听final ui.Image image = frame.image;plete(image); //完成stream.removeListener(listener); //移除监听});stream.addListener(listener); //添加监听return completer.future; //返回}

总结

绘制图片前,需要将图片转换为ui.Image,记得导入import ‘dart:ui’ as ui;绘制海报时,注意大小的跳转,保证图片比例不变保存图片用到了RepaintBoundary来实现将组件保存为图片功能其它疑问可加博主微信号tinywangyining沟通,添加时备注【掘金】

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。