Flutter如何使用类似9patch图的效果,看这篇就够了

Android开发中,遇到聊天背景,复杂的布局背景这类的需求,一般都是通过9Patch图去实现的,简单好用,效果最能达到UI的要求,尤其是带有阴影的背景,9Patch简直是程序员之光。

遗憾的是,这么好用的东西,只能在Android的开发中使用,放到Flutter中就不灵光了。那么,Flutter中想要实现这样的效果,应该怎么做呢?

研究了一番,其实,Flutter中也提供了类似与9Patch图的实现效果,只是这个效果要结合Container的padding和decoration这两个属性了。

先来看一下我们要实现的最终效果:

 需要用到的切图:

那么具体应该怎么实现呢?

在Flutter中实现这样的效果,需要将整体放入一个Container中,这是前提,然后分两个维度去布局文字和Container四周的边距,以及切图拉伸的点位和宽高。

第一个维度:文字(也可以是其他内容)和Container四周的边距(即padding),这个比较简单,设置Container的padding属性即可,不过这里设置的值有些讲究,如下图:

 

 这里如果要想文字在气泡的中间显示,那么左侧还要忽略多出来的这个箭头的宽度,所以设置padding的时候应该是这样的:

padding: const EdgeInsets.fromLTRB(20, 12, 16, 12),

第二个维度:气泡的拉伸,这里需要明确的是,气泡左侧箭头及以上部分是不能拉伸的,否则,这个箭头就会变形,所以,拉伸的时候只能从箭头下面开始拉伸(这里对应的是LTRB或者LTWH的T,关于LTRB和LTWH的区别可自行查询,这里不再赘述),如下图,

 粉色的方框便是拉伸的区域,这个拉伸区域可以通过如下代码设置:

centerSlice: Rect.fromLTWH(20, 25, ?, ?)

或者

centerSlice: Rect.fromLTRB(20, 25, ?, ?)

左侧和上面比较好确定,避开左侧三角箭头即可,我这里大概试了几下,确定了左:20,上:25,那么如何确定右侧和底部的数值呢?

刚开始的时候我尝试将这个拉伸区域拉开一点点,比如拉开宽高为1,代码如下:

centerSlice: Rect.fromLTWH(20, 25, 1, 1),

或者

centerSlice: Rect.fromLTRB(20, 25, 21, 26),

当我敲了很长一段文字后,确实好用,按照预想的展示出来了,大功告成。

当我输入了一个“123”之后,发现不好用了,连图带字全都不显示了,控制台出现了一串报错:

The following assertion was thrown during paint():
Assertion failed: file:///D:/Work/Flutter/flutter_sdk/flutter/packages/flutter/lib/src/painting/decoration_image.dart:535:12
sourceSize == inputSize
"centerSlice was used with a BoxFit that does not guarantee that the image is fully visible."

点开日志指向的文件:里面有段注释写到:

 意思是"我们无法在应用9Patch拉伸的同时绘制图像的子集。",为甚么文字多的时候没问题,文字少的时候就不行了?根据注释,我猜测是文字多的时候渲染的比较慢,给了9Patch图充分的拉伸时间,文字少的时候渲染快,这时候9Patch还没有完成拉伸或者正在拉伸,我设置的拉伸宽高只有1,这就导致了文字渲染不进去,或者9Patch不完全可见,验证了错误的日志:

centerSlice was used with a BoxFit that does not guarantee that the image is fully visible.

翻译过来就是:centerSlice 与不保证图像完全可见的 BoxFit 一起使用。

最终,我把拉伸的宽高改大一点比如5或者10之类的,也不能太大,否则气泡切图会变形,够用即可。完整代码如下:

Container(
 padding: const EdgeInsets.fromLTRB(20, 12, 16, 12),
 margin: const EdgeInsets.only(left: 10),
 decoration: const BoxDecoration(
            image: DecorationImage(
              image: AssetImage('assets/....../qipao.png'),
               centerSlice: Rect.fromLTWH(20, 25, 10, 10),
              ),
          ),
  child: Text("测试文字"),
),

其中的

centerSlice: Rect.fromLTWH(20, 25, 10, 10),

也可以改为

centerSlice: Rect.fromLTRB(20, 25, 30, 35),

至此,Flutter中使用9Patch类似效果的实现方法已经写完了,需要注意的是不要把padding和拉伸这两个维度弄混了,这两个其实是没有必然联系的,我刚开的时候调这些参数的时候也是很乱的,理清这两个维度的关系,这个效果就很容易实现了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值