[》越过拾光回忆]
拾光回忆
1-15.资产办理 Fam、手势触摸、枚举高阶用法、快速完成单选和多选、Diy 滑动轨迹、水印功用、Image 高阶用法、矩阵16个参数意义、颜色差异、颜色填充、图画镜像、图画旋转、图画去色等功用的调集
简介: 该篇首要介绍15 篇文章
含有功用的目录,可依据自己的需求挑选对应的功用介绍查看。
引荐: ⭐️⭐️⭐️⭐️⭐️
16. Flutter 之 IImage 图画反色处理
简介: 该篇首要介绍 Flutter 之 IImage 库中如何完成图画反色功用以及完成原理的介绍。
引荐: ⭐️⭐️⭐️⭐️⭐️
17. Flutter 制作途径 Path 的悉数办法介绍,一篇足矣~(一)
18. Flutter 制作途径 Path 的悉数办法介绍,一篇足矣~(二)
19. Flutter 制作途径 Path 的悉数办法介绍,一篇足矣~(三)
简介: 该篇首要介绍 Flutter
之 图形(Canvas
) 制作途径 (Path
)基础功用以及办法完成底层代码的解析。
引荐: ⭐️⭐️⭐️⭐️⭐️
[返回拾光回忆《]
一、简述
跟着技能的发展,谈天软件如漫山遍野般不断涌现。为了提高用户的视觉体验,许多软件采用了谈天内容以气泡办法展现,并规划了多种谈天气泡样式供用户挑选更换。而当用户输入的文字改变时,气泡能够跟随内容进行相应改变,这一功用真是奇特!那么在Flutter中,咱们如何完成这样的效果呢?接下来,咱们将介绍谈天气泡的完成进程,并处理其中遇到的问题。
二、完成阐述
谈天气泡目前完成办法大致分为两种:
- 气泡办法运用 Canvas 制作来完成气泡的改变
- 借助UI切图,拉伸图片来完成气泡的改变
从上述介绍的两种办法,第 2 种办法完成比较第 1 种办法很简单完成, 而第 2 种办法的中心便是点九图。
三、点九图
点九图是一种可拉伸的位图,自动调整它的巨细,来使图画在充任布景时能够在界面中自适应。 在 Flutter 中点九图表现为将图片切割成九份,如下图所示:
咱们能够设置第5块区域的巨细和方位也就能确认第 2、4、6、8 四个模块; 假如气泡产生水平改变,那么第 2、5、8 三个模块进行水平拉伸处理;假如气泡笔直产生改变,那么第 4、5、6 三个模块进行笔直拉伸处理;假如气泡笔直和水平都有改变时, 第 2、8 做水平拉伸;第 4、6 做笔直拉伸;第 5 一起水平和笔直拉伸处理。上面介绍的在 Flutter 的 canvas.drawImageNine
和 DecorationImage:centerSlice
中涉及到。
四、DecorationImage:centerSlice – 气泡
下面是一个气泡实例,如下所示:
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 600, maxHeight: 600),
decoration: const BoxDecoration(
image: DecorationImage(
centerSlice: Rect.fromLTWH(10, 15, 3, 3),
image: AssetImage(FamManager.db),
),
),
child: const Text(
'Flutter 聊化聊化聊化聊化聊化化聊化聊化聊化聊化聊化聊化聊化',
style: TextStyle(color: Colors.red),
).insetsSymmetric(vertical: 20, horizontal: 20),
),
),
);
}
}
从上面代码的第 13 行,咱们设置点九图的中心区域巨细, 如下图所示:
咱们运转上面视图,发现显现不出效果,一起还有反常提醒,如下所示:
咱们依据反常提示,很简单找到反常的方位,如下图所示:
在上面图片代码中,有 final FittedSizes fittedSizes = applyBoxFit(fit, inputSize / scale, outputSize);
这一行代码,这行代码是获取到的 fittedSizes
决定着 sourceSize
的值。该办法的底层完成如下:
FittedSizes applyBoxFit(BoxFit fit, Size inputSize, Size outputSize) {
if (inputSize.height <= 0.0 || inputSize.width <= 0.0 || outputSize.height <= 0.0 || outputSize.width <= 0.0) {
return const FittedSizes(Size.zero, Size.zero);
}
Size sourceSize, destinationSize;
switch (fit) {
case BoxFit.fill:
sourceSize = inputSize;
destinationSize = outputSize;
break;
// .... 省略无关代码
}
return FittedSizes(sourceSize, destinationSize);
}
咱们开始剖析该方传入的参数,如下所示:
-
fit
咱们从上图代码的fit ??= centerSlice == null ? BoxFit.scaleDown : BoxFit.fill;
可知applyBoxFit
办法中传入的fit
参数值是fill
, 所以才躲藏其他类型的无关代码。 -
inputSize
有上面图片中的Size outputSize = rect.size; Size inputSize = Size(image.width.toDouble(), image.height.toDouble()); Offset? sliceBorder; if (centerSlice != null) { sliceBorder = inputSize / scale - centerSlice.size as Offset; outputSize = outputSize - sliceBorder as Size; inputSize = inputSize - sliceBorder * scale as Size; }
这些代码可知
inputSize
的巨细便是咱们设置中心区域的巨细(scale =1 时),则inputSize
传入的值的巨细是Size(3,3)
。 -
outputSize
outputSize
是咱们组件的尺度减去裁剪边框sliceBorder
得到的。则outputSize
传入的值的巨细是Size(355,-4)
。
上面参数值的成果咱们能够经过打断点的办法获取。然后咱们以获取到 applyBoxFit
办法传入的参数值,则有
if (inputSize.height <= 0.0 || inputSize.width <= 0.0 || outputSize.height <= 0.0 || outputSize.width <= 0.0) {
return const FittedSizes(Size.zero, Size.zero);
}
代码进行判定,因为 outputSize.height
的高度是 -4
, 而返回 FittedSizes(Size.zero, Size.zero);
。
-
从上述代码剖析,是
outputSize
的高度出现负数导致反常。 而outputSize
的高度核算公式如下:height = rect.height - (image.height / scale - centerSlice.height)
, 结合上边的例子将数值带入公式,height : 60 - (67 / 1 - 3 ) = -4
,而得到验证。 -
从
height = rect.height - (image.height / scale - centerSlice.height)
公式想让height
大于零有两种办法。如下所示:-
调整
rect.height
, 让组件初始高度增加。比方:咱们给文本增加Padding
。 示例如下:class MyWidget extends StatelessWidget { const MyWidget({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Center( child: Container( constraints: const BoxConstraints(maxWidth: 600, maxHeight: 600), decoration: const BoxDecoration( image: DecorationImage( centerSlice: Rect.fromLTWH(10, 15, 3, 3), image: AssetImage(FamManager.db), ), ), child: const Text( 'Flutter 聊化聊化聊化聊化聊化化聊化聊化聊化聊化聊化聊化聊化', style: TextStyle(color: Colors.red), ).insetsSymmetric(vertical: 25, horizontal: 20), ), ), ); } }
上述代码运转视图如下:
上边视图显现正常,咱们大略核算一下高度:
25 * 2 + 14 * 1.4 - (67/1 - 3) = 5.9
, 咱们运用断点得到的高度如图所示: -
调整图画的
scale
值, 一起也要等比缩放centerSlice
的值 ,让裁剪边距变大。实例如下:class MyWidget extends StatelessWidget { const MyWidget({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Center( child: Container( constraints: const BoxConstraints(maxWidth: 600, maxHeight: 600), decoration: const BoxDecoration( image: DecorationImage( centerSlice: Rect.fromLTWH(10 / 2, 15 / 2, 3 / 2, 3 / 2), image: AssetImage(FamManager.db), scale: 2, ), ), child: const Text( 'Flutter 聊化聊化聊化聊化聊化化聊化聊化聊化聊化聊化聊化聊化', style: TextStyle(color: Colors.red), ).insetsSymmetric(vertical: 20, horizontal: 20), ), ), ); } }
上述代码运转实例如下:
咱们大略核算一下:
20 * 2 + 14 * 1.4 - (67/2 - 3/2) = 27.6
, 咱们再运用断点获取一下高度如下所示:
-
五、Canvas::drawImageNine
下面是应用实例如下:
class MyWidgetCanvas extends StatelessWidget {
const MyWidgetCanvas({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: FutureBuilder(
future: getImageFromAssets(FamManager.db),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.active) {
return const Text('加载中');
}
return CustomPaint(
painter: ChatBubblePainter(snapshot.data!),
child: const Text(
'Flutter 聊化聊化聊化聊化聊化聊化化聊化聊化聊化化聊化聊化聊化化聊聊化',
style: TextStyle(color: Colors.red),
).insetsSymmetric(vertical: 20, horizontal: 20),
);
},
),
),
);
}
Future<ui.Image> getImageFromAssets(String path) async {
final ImmutableBuffer immutableBuffer = await rootBundle.loadBuffer(path);
final ui.Codec codec = await ui.instantiateImageCodecFromBuffer(
immutableBuffer,
);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}
}
class ChatBubblePainter extends CustomPainter {
const ChatBubblePainter(this.image);
final ui.Image image;
@override
void paint(Canvas canvas, Size size) {
canvas.drawImageNine(image, const Rect.fromLTWH(10 / 2, 15 / 2, 3 / 2, 3 / 2), Offset.zero & size, Paint());
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
上述代码运转的视图成果如下:
从上述能够看到,气泡的完成运用制作比UI相对繁琐。我们能够依据需求挑选完成办法。
六、鼓励与支撑
上面介绍了谈天气泡的完成办法以及在运用进程中遇到问题的总结和处理问题的探索。希望该篇文章功用让你对Flutter 中的点九图有更深入的了解。假如你感觉文章写的还能够,那请留下你的保藏与评论。该篇文章运用的资源办理是由 fam
供给;运用的便捷增加边距是由 idkit
供给。本篇的实例代码地址如下: 谈天气泡实例仓库。