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

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

作者: 编程的平行世界 | 来源:发表于2022-12-03 11:40 被阅读0次

    前言:

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

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

    话不多说,直接上图:

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

    2.png

    功能实现步骤分析:

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

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

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

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

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

    • 定义需要存放的数据

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

      3.png
    ```
    Container(
      margin: const EdgeInsets.all(25.0),
      child: TextField(
        controller: textEditingController,
        decoration: const InputDecoration(
            hintText: "请输入文字",
            border: OutlineInputBorder(
                borderRadius: BorderRadius.all(Radius.circular(16.0)))),
      ),
    ),
    ```
    
    • 九宫格图片封装

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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/whvpfdtx.html