Flutter — 仅用三个步骤就能帮你把文本变得炫酷!
- 2022-12-04 浙江
本文字数:3477 字
阅读完需:约 11 分钟
前言:
前天,一位不愿意透露姓名的朋友找到我,问我怎么样才能把文本变得炫酷一些,他想用图片嵌入到自己的名字里去,用来当作朋友圈的背景。我直接回了一句,你 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,如果您觉得文章对您有价值,希望您能给我的文章点个❤️,有问题需要联系我的话:我在这里 ,也可以通过掘金的新的私信功能联系到我。如果您觉得文章还差了那么点东西,也请通过关注督促我写出更好的文章~万一哪天我进步了呢?😝
版权声明: 本文为 InfoQ 作者【编程的平行世界】的原创文章。
原文链接:【http://xie.infoq.cn/article/3de3806b4aea03c9c05d87b9b】。文章转载请联系作者。
编程的平行世界
他日若遂凌云志 敢笑黄巢不丈夫 2020-10-15 加入
曾许少年凌云志,誓做人间第一流. 一起加入Flutter技术交流群532403442 有好多好多滴学习资料喔~ 小T目前主攻Android与Flutter, 通常会搞搞人工智能、SpringBoot 、Mybatiys等.
评论