写点什么

Flutter — 仅用三个步骤就能帮你把文本变得炫酷!

  • 2022-12-04
    浙江
  • 本文字数:3477 字

    阅读完需:约 11 分钟

Flutter — 仅用三个步骤就能帮你把文本变得炫酷!

前言:

前天,一位不愿意透露姓名的朋友找到我,问我怎么样才能把文本变得炫酷一些,他想用图片嵌入到自己的名字里去,用来当作朋友圈的背景。我直接回了一句,你 PS 下不就好了。他回我一句:想要这样效果的人比较多,全部都 PS 的话怕不是电脑要干冒烟...能不能用代码自动生成下(请你喝奶茶🍹)。作为一个乐于助人的人,看到朋友有困难,而且实现起来也不复杂,那我必须要帮忙啊~


注:本文是一篇整活文,让大家看的开心最重要~文章只对核心代码做分析,完整代码在这里

话不多说,直接上图:

填入文本中的可以是手动上传的图片,也可以是彩色小块。


功能实现步骤分析:

1.数据的获取 — 获取输入的文本数据、获取输入的图片数据。


2.将输入的文本生成为图片


3.解析文本图片,替换像素为图片


简单三步骤,实现朴素到炫酷的转换~

1.数据的获取 — 获取输入的文本数据、获取输入的图片数据。

  • 定义需要存放的数据


    //用于获取输入的文本    TextEditingController textEditingController = TextEditingController();    //存放输入的图片    List<File> imagesPath = [];
复制代码


  • 输入框


    Container(      margin: const EdgeInsets.all(25.0),      child: TextField(        controller: textEditingController,        decoration: const InputDecoration(            hintText: "请输入文字",            border: OutlineInputBorder(                borderRadius: BorderRadius.all(Radius.circular(16.0)))),      ),    ),
复制代码


  • 九宫格图片封装



    @override    Widget build(BuildContext context) {      var maxWidth = MediaQuery.of(context).size.width;      //计算不同数量时,图片的大小      var _ninePictureW = (maxWidth - _space * 2 - 2 * _itemSpace - lRSpace);      ...      return Offstage(        offstage: imgData!.length == -1,        child: SizedBox(          width: _bgWidth,          height: _bgHeight,          child: GridView.builder(              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(                // 可以直接指定每行(列)显示多少个Item                crossAxisCount: _crossAxisCount, // 一行的Widget数量                crossAxisSpacing: _itemSpace, // 水平间距                mainAxisSpacing: _itemSpace, // 垂直间距                childAspectRatio: _childAspectRatio, // 子Widget宽高比例              ),              // 禁用滚动事件              physics: const NeverScrollableScrollPhysics(),              // GridView内边距              padding: const EdgeInsets.only(left: _space, right: _space),              itemCount:                  imgData!.length < 9 ? imgData!.length + 1 : imgData!.length,              itemBuilder: (context, index) {                if (imgData!.isEmpty) {                  return _addPhoto(context);                } else if (index < imgData!.length) {                  return _itemCell(context, index);                } else if (index == imgData!.length) {                  return _addPhoto(context);                }                return SizedBox();              }),        ),      );    }
复制代码


  • 添加图片

  • 使用 A 佬的wechat_assets_picker,要的就是效率~


    Future<void> selectAssets() async {      //获取图片      final List<AssetEntity>? result = await AssetPicker.pickAssets(        context,      );      List<File> images = [];      //循环取出File      if (result != null) {        for (int i = 0; i < result.length; i++) {          AssetEntity asset = result[i];          File? file = await asset.file;          if (file != null) {            images.add(file);          }        }      }      //更新状态,修改存放File的数组      setState(() {        imagesPath = images;      });    }
复制代码

2.将输入的文本生成为图片

  • 构建输入的文本布局


    RepaintBoundary(        key: repaintKey,        child: Container(          color: Colors.white,          width: MediaQuery.of(context).size.width,          height: 300,            //image是解析图片的数据          child: image != null              ? PhotoLayout(                  n: 1080,                  m: 900,                  image: image!,                  fileImages: widget.images)              :             //将输入的文本布局            Center(                  child: Text(                    widget.photoText,                    style: const TextStyle(                        fontSize: 100, fontWeight: FontWeight.bold),                  ),                ),        )),
复制代码


  • 通过RepaintBoundary将生成的布局生成Uint8List数据


    /// 获取截取图片的数据,并解码      Future<img.Image?> getImageData() async {        //生成图片数据        BuildContext buildContext = repaintKey.currentContext!;        Uint8List imageBytes;        RenderRepaintBoundary boundary =            buildContext.findRenderObject() as RenderRepaintBoundary;        double dpr = ui.window.devicePixelRatio;        ui.Image image = await boundary.toImage(pixelRatio: dpr);        // image.width        ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);        imageBytes = byteData!.buffer.asUint8List();        var tempDir = await getTemporaryDirectory();        //生成file文件格式        var file =            await File('${tempDir.path}/image_${DateTime.now().millisecond}.png')                .create();        //转成file文件        file.writeAsBytesSync(imageBytes);        //存放生成的图片到本地        // final result = await ImageGallerySaver.saveFile(file.path);        return img.decodeImage(imageBytes);      }
复制代码

3.解析文本图片,替换像素为图片

  • 判断文本像素,在对应像素位置生成图片


    Widget buildPixel(int x, int y) {      int index = x * n + y;      //根据给定的x和y坐标,获取像素的颜色编码      Color color = Color(image.getPixel(y, x));      //判断是不是白色的像素点,如果是,则用SizedBox替代      if (color == Colors.white) {        return const SizedBox.shrink();      }      else {        //如果不是,则代表是文本所在的像素,替换为输入的图片        return Image.file(            fileImages![index % fileImages!.length],            fit: BoxFit.cover,          );      }    }
复制代码


  • 构建最终生成的图片


    @override    Widget build(BuildContext context) {      List<Widget> children = [];        //按点去渲染图片的像素位置,每次加10是因为,图像的像素点很多,如果每一个点都替换为图片,第一是效果不好,第二是渲染的时间很久。      for (int i = 0; i < n; i = i+10) {        List<Widget> columnChildren = [];        for (int x = 0; x < m; x = x+10) {          columnChildren.add(            Expanded(              child: buildPixel(x, i),            ),          );        }        children.add(Expanded(            child: Column(          crossAxisAlignment: CrossAxisAlignment.stretch,          children: columnChildren,        )));      }      //CrossAxisAlignment.stretch:子控件完全填充交叉轴方向的空间      return Row(        crossAxisAlignment: CrossAxisAlignment.stretch,        children: children,      );    }
复制代码


这样就实现了文本替换为图片的功能啦~

关于我

Hello,我是 Taxze,如果您觉得文章对您有价值,希望您能给我的文章点个❤️,有问题需要联系我的话:我在这里 ,也可以通过掘金的新的私信功能联系到我。如果您觉得文章还差了那么点东西,也请通过关注督促我写出更好的文章~万一哪天我进步了呢?😝

发布于: 刚刚阅读数: 4
用户头像

他日若遂凌云志 敢笑黄巢不丈夫 2020-10-15 加入

曾许少年凌云志,誓做人间第一流. 一起加入Flutter技术交流群532403442 有好多好多滴学习资料喔~ 小T目前主攻Android与Flutter, 通常会搞搞人工智能、SpringBoot 、Mybatiys等.

评论

发布
暂无评论
Flutter — 仅用三个步骤就能帮你把文本变得炫酷!_flutter_编程的平行世界_InfoQ写作社区