flutter系列之:做一个图像滤镜|全球快消息
[toc] 简介很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的
2023-06-16很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的,如果是h5页面,那么我们可以很容易的通过css滤镜来实现这个功能。
那么如果在flutter中,如果要实现这样的滤镜功能应该怎么处理呢?一起来看看吧。
(资料图片仅供参考)
在继续进行之前,我们先来讨论下本章到底要做什么。最终的目标是希望能够实现一个图片的滤镜功能。
那么我们的app界面实际上可以分为两个部分。第一个部分就是带滤镜效果的图片,第二个部分就是可以切换的滤镜按钮。
接下来我们一步步来看如何实现这些功能。
带滤镜的图片要实现这个功能其实比较简单,我们构建一个widget,因为这个widget中的图片需要根据自身选择的滤镜颜色来改变图片的状态,所以这里我们需要的是一个StatefulWidget,在state里面,存储的就是当前的_filterColor。
构建一个图片的widget的代码可以如下所示:
class ImageFilterApp extends StatefulWidget { const ImageFilterApp({super.key}); @override State createState() => _ImageFilterAppState();}class _ImageFilterAppState extends State { final _filters = [ Colors.white, ...Colors.primaries ]; final _filterColor = ValueNotifier(Colors.white); void _onFilterChanged(Color value) { _filterColor.value = value; } @override Widget build(BuildContext context) { return Material( color: Colors.black, child: Stack( children: [ Positioned.fill( child: _buildPhotoWithFilter(), ), ], ), ); } Widget _buildPhotoWithFilter() { return ValueListenableBuilder( valueListenable: _filterColor, builder: (context, value, child) { final color = value; return Image.asset( "images/head.jpg", color: color.withOpacity(0.5), colorBlendMode: BlendMode.color, fit: BoxFit.cover, ); }, ); }} 在build方法中,我们返回了一个Positioned.fill填充的widget,这个widget可以把app的视图填满。
在_buildPhotoWithFilter方法中,我们返回了Image.asset,里面可以设置image的color和colorBlendMode。这两个值就是图片滤镜的关键。
就这么简单?一个图片滤镜就完成了?对的就是这么简单。图片滤镜就是Image.asset中自带的功能。
但是在实际的应用中,这个color不会是固定的,是需要根据我们的不同选择而进行变化的。为了能够接受到这个变化的值,我们使用了ValueListenableBuilder,通过传入一个可变的ValueNotifier,来实现监听color变化的结果。
final _filterColor = ValueNotifier(Colors.white); void _onFilterChanged(Color value) { _filterColor.value = value; } 另外,我们提供了一个触发_filterColor的值进行变化的方法_onFilterChanged。
上面的代码运行的结果如下:
很好,现在我们已经有了一个带有颜色filter功能的界面了。 接下来我们还需要一个filter的按钮,来触发filter颜色的变化。
打造filter按钮这里我们的filter包含了Colors.primaries中所有的颜色再加上一个自定义的白色。
每一个filter按钮其实都可以用一个widget来表示。我们希望是一个圆形的filter按钮,里面有一个图片的小的缩略图来展示filter的效果。
另外通过tap对应的filter按钮,还可以实现color切换的功能。
所以对于Filter按钮widget来说,可以接收两个参数,一个是当前的color,另外一个是tap之后的VoidCallback onFilterSelected, 所以最终我们的FilterItem是下面的样子的:
class FilterItem extends StatelessWidget { const FilterItem({ super.key, required this.color, this.onFilterSelected, }); final Color color; final VoidCallback? onFilterSelected; @override Widget build(BuildContext context) { return GestureDetector( onTap: onFilterSelected, child: AspectRatio( aspectRatio: 1.0, child: Padding( padding: const EdgeInsets.all(8.0), child: ClipOval( child: Image.asset( "images/head.jpg", color: color.withOpacity(0.5), colorBlendMode: BlendMode.hardLight, ), ), ), ), ); }打造可滑动按钮上一节我们创建好了filter按钮,接下来就是把filter按钮组装起来,形成一个可滑动的filter按钮组件。
要想滑动widget,我们可以使用Scrollable组件,通过传入一个PageController来控制PageView的展示。
Scrollable出了controller之外,还有一个非常重要的属性就是viewportBuilder。在viewportBuilder中可以传入viewportOffset。
当Scrollable滑动的时候,viewportOffset中的pixels是会动态变化的。我们可以根据viewportOffset中的pixels的变化来重绘filter按钮。
如果要根据viewportOffset的变化来重新定位child组件的位置的话,最好的方式就是将其包裹在Flow组件中。
因为Flow提供了一个FlowDelegate,我们可以在FlowDelegate中根据viewportOffset的不同来重绘filter widget。这个FlowDelegate的实现如下:
class CarouselFlowDelegate extends FlowDelegate { CarouselFlowDelegate({ required this.viewportOffset, required this.filtersPerScreen, }) : super(repaint: viewportOffset); final ViewportOffset viewportOffset; final int filtersPerScreen; @override void paintChildren(FlowPaintingContext context) { print(viewportOffset.pixels); final count = context.childCount; //绘制宽度 final size = context.size.width; // 一个单独item的宽度 final itemExtent = size / filtersPerScreen; // active item的index final active = viewportOffset.pixels / itemExtent; print("active$active"); // 要绘制的最小的index,在active item的左边最多绘制3个items final min = math.max(0, active.floor() - 3).toInt(); //要绘制的最大index,在active item的右边最多绘制3个items final max = math.min(count - 1, active.ceil() + 3).toInt(); // 重新绘制要展示的item for (var index = min; index <= max; index++) { final itemXFromCenter = itemExtent * index - viewportOffset.pixels; final percentFromCenter = 1.0 - (itemXFromCenter / (size / 2)).abs(); final itemScale = 0.5 + (percentFromCenter * 0.5); final opacity = 0.25 + (percentFromCenter * 0.75); final itemTransform = Matrix4.identity() ..translate((size - itemExtent) / 2) ..translate(itemXFromCenter) ..translate(itemExtent / 2, itemExtent / 2) ..multiply(Matrix4.diagonal3Values(itemScale, itemScale, 1.0)) ..translate(-itemExtent / 2, -itemExtent / 2); context.paintChild( index, transform: itemTransform, opacity: opacity, ); } } @override bool shouldRepaint(covariant CarouselFlowDelegate oldDelegate) { //viewportOffset被替换的情况下触发 return oldDelegate.viewportOffset != viewportOffset; }}在paintChildren的最后,我们通过调用context.paintChild来重绘child。
可以看到这里传入了三个参数,第一个参数是child的index,这个index指的是创建Flow时候传入的children数组中的index:
Flow( delegate: CarouselFlowDelegate( viewportOffset: viewportOffset, filtersPerScreen: _filtersPerScreen, ), children: [ for (int i = 0; i < filterCount; i++) FilterItem( onFilterSelected: () => _onFilterTapped(i), color: itemColor(i), ), ], )最后,我们把创建Flow的方法_buildCarousel放到Scrollable中去,并将viewportOffset作为Flow的构造函数参数传入,从而实现Flow根据Scrollable的滑动而发送相应的变化:
Widget build(BuildContext context) { return Scrollable( controller: _controller, axisDirection: AxisDirection.right, physics: const PageScrollPhysics(), viewportBuilder: (context, viewportOffset) { return LayoutBuilder( builder: (context, constraints) { final itemSize = constraints.maxWidth * _viewportFractionPerItem; viewportOffset ..applyViewportDimension(constraints.maxWidth) ..applyContentDimensions(0.0, itemSize * (filterCount - 1)); return Stack( alignment: Alignment.bottomCenter, children: [ _buildCarousel( viewportOffset: viewportOffset, itemSize: itemSize, ), ], ); }, ); }, );最后要解决的问题到目前为止,一切看起来都很好。但是如果你仔细研究的话可能会产生一个疑问。那就是Scrollable的controller是PageController,我们是通过PageController中的page来切换对应的filter颜色的:
void _onPageChanged() { print("page${_controller.page}"); final page = (_controller.page ?? 0).round(); if (page != _page) { _page = page; widget.onFilterChanged(widget.filters[page]); } }那么这个page是如何变化的呢?什么时候从0变成1呢?
我们先来看下PageController的构造函数:
_controller = PageController( initialPage: _page, viewportFraction: _viewportFractionPerItem, );除了初始化的initialPage之外,还有一个viewportFraction。这个值就是指一个view可以被分成多少个page。
以我的iphone14为例,它的constraints.maxWidth=390.0, 如果被分成5份的话,一份的值是78.0。 也就是说当Scrollable滑动78,的时候,page就从0变成1了。这和我们在Flow中重绘child时候,取的index是一致的。
最后,效果图如下:
本文的例子:https://github.com/ddean2009/learn-flutter.git
标签:
[toc] 简介很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的
2023-06-16
06:28“中国文化源远流长,中华文明博大精深”。习近平总书记强调:“
2023-06-16
摘要:2023年06月16日鸣志电器(603728)股价大幅拉升7 3%,该股报67 5
2023-06-16
欢迎观看本篇文章,小升来为大家解答以上问题。漏拼音,漏怎么组词很多
2023-06-16
一、兄妹拆迁房纠纷怎么处理一般情况下,房屋拆迁发生纠纷时,双方应当
2023-06-16
联想陈劲:小折叠屏手机已到爆发前夜,未来普及将成趋势,陈劲,智能手机
2023-06-16
6月15日晚,奔流新闻记者从青藏线失联货车司机的亲属处获悉,当日下午
2023-06-16
《暗黑破坏神4》中的高机动电花法师是游戏里非常好用的强力法师流派,
2023-06-16
截至2022年底,昆明回收废旧农用薄膜面积达196 7万亩。6月15日,记者从
2023-06-16
来源:上海证券报随着美联储加息暂缓的“靴子落地”,叠加流动性环境不
2023-06-16
那父母又该如何正确的解决青少年的躁狂症呢?1 定期带孩子体检定期带孩
2023-06-16
1、螃蟹洗干净后放笼屉蒸,一定要壳朝下,肚子朝上,这样做是为了不让
2023-06-16
龙磁科技在互动平台表示,公司高性能铁氧体湿压磁瓦主要应用于汽车电机
2023-06-16
6月15日,派克新材(605123)融资买入356 46万元,融资偿还669 76万元
2023-06-16
《北京青年报》撰文认为,尽管中国足球遭遇冰点期,但梅西中国行仍然非
2023-06-16
1、阴月皇朝的第一美女蓝魔和玄心正宗的诸葛青天所生的儿子。2、诸葛青
2023-06-16
曾经躺着都能赚钱的中国真皮“鞋王”,如今却麻烦不断。6月10日,ST奥
2023-06-16
AMD可能会将3D缓存作为游戏平台上的“重头戏”。针对最新的爆料消息,A
2023-06-16
按照《神池县2022年部分事业单位公开招聘工作人员实施方案》,经公告发
2023-06-16
福建:“耕海牧渔”打造“蓝色粮仓”
2023-06-16
公测开始后,很多玩家都迫不及待进入游戏准备开始游玩了,但是有一些小
2023-06-15
北向资金今日大幅净买入92 01亿元。宁德时代(行情300750,诊股)、五粮液
2023-06-15
1、病情分析:肾虚会因久病、过度劳累、过食寒性食物、熬夜失眠等因素
2023-06-15
问:石家庄发放的文化惠民卡怎么使用?答:石家庄“文惠卡”内金额可用
2023-06-15
1、准确的说这首歌叫《多爱我一秒钟》,这首歌收录在内地版《我在身边
2023-06-15
浙江纺织印染(数码喷印)绿色准入指导意见试行,提高行业绿色发展水平
2023-06-15
每经编辑:黄胜6月15日,阿根廷国家男子足球队将在北京工体与澳大利亚
2023-06-15
6月15日,据北京日报客户端报道:人力资源社会保障部办公厅、财政部办
2023-06-15
国海证券06月15日发布研报称,给予东方日升(300118 SZ,最新价:23 7
2023-06-15
建议关注:整机领域的紫光股份(具备稀缺的完整ICT解决方案能力)、浪
2023-06-15
大河网讯“今天的防电信诈骗知识宣讲让我大开眼界,新的诈骗手段还真没
2023-06-15
1、当然第一种是最方便快捷的炒栗子,也是基本吃法,因为没有去壳,哈
2023-06-15
川观新闻记者田姣6月13日,央行公开市场操作7天期逆回购利率下调,“降
2023-06-15
对于不少手心游戏日报的玩家来说,老师菜菜捞捞是什么梗一览是常常困扰
2023-06-15
金投网提供熊猫发行30周年金银币价格今天多少一克(2023年06月15日),
2023-06-15
以视力不太好为理由提出调换座位,如果平时视力不太好,又恰巧坐在教室
2023-06-15
法国总统埃马纽埃尔·马克龙表示,将于当地时间6月16日与特斯拉首席执
2023-06-15
舜网国内频道发布国内最新鲜的新闻,国内热点事件和民生事件。
2023-06-15
1、苦瓜凉拌吃最好。2、苦瓜根、藤、叶及果实:苦,寒。3、清热解毒,
2023-06-15
企查查APP显示,近日,深圳华自超算技术有限公司成立,法定代表人为宋
2023-06-15
微软创始人比尔・盖茨6月14日在推特上写道,他已经到达北京,这是他自2
2023-06-15
6月15日,生意社苯酐基准价为7637 50元 吨,与本月初(7875 00元 吨)相
2023-06-15
昆明信息港讯(昆明日报记者李思凡罗昆娅)近期,昆明多个景区推出针对
2023-06-15
隔夜原油飘绿,美油、布油分别跌1 07%、0 92%;美元下跌,美元指数跌0
2023-06-15
1、个人意见,芼在关雎中,应是采摘、挑选之意。2、表现对心上人的追求
2023-06-15
来为大家解答以上问题,佳能,g10很多人还不知道,现在让我们一起来看
2023-06-15
1、《安放心灵的28封信:中国年青一代的集体倾诉与反思》是2011年10月1
2023-06-15
1、库存周转率,一种衡量材料在工厂里或是整条价值流中,流动快慢的标
2023-06-15
江苏省人大常委会关于2023-2027年立法规划项目安排(草案)征求意见的
2023-06-14
1、字幕文件。2、字幕一般分为两大类:文本字幕:如srt、ssa、ass、sub
2023-06-14
存款利率一降再降、智能通知存款停售,使得居民将更多目光转向理财,理
2023-06-14
sport1:德国队11月份将在柏林与土耳其进行热身赛,柏林,土耳其,欧预赛,sport1
2023-06-14
西山科技:东方证券承销保荐有限公司关于重庆西山科技股份有限公司使用
2023-06-14
社会服务行业人力资源服务行业跟踪点评:关注顺周期人服赛道布局行业成
2023-06-14
2023上海绿色建筑国际论坛昨天召开,聚焦“绿色低碳,助力城市高质量发
2023-06-14
南沙港澳居民个人所得税优惠、企业所得税优惠、高新技术重点行业企业进
2023-06-14
据美联社当地时间6月12日报道,在新冠疫情期间,美国政府发放的4 2万亿
2023-06-14
企查查APP显示,近日,广州互联网法院将李某列为失信被执行人(老赖)
2023-06-14
1、所有队员站在胶布上的一角,一位抓住胶布上的另一角一翻,这时胶布
2023-06-14
618如火如荼的进行中,燕京啤酒“董事长来了!”直播活动再度来袭。6月
2023-06-14
1、可以做的生意多了。2、摆摊去吧。本文就为大家分享到这里,希望看了
2023-06-14
【中伟股份:公司印尼莫罗瓦利产业基地首条冰镍产线正式投料试产并成功
2023-06-14
生物特征识别技术,关于生物特征识别技术介绍这个很多人还不知道,我们
2023-06-14
新华社北京6月14日电据美国媒体报道,共和党籍前总统特朗普13日在佛罗
2023-06-14
1、图中这个刘海整齐的小女孩是李想的女儿。这个小女生的短发造型超级
2023-06-14
大家好,小万来为大家解答以上的问题。小儿常见病饮食疗法,关于小儿常
2023-06-14
银行业:社融增速转降需求尚需修复
2023-06-14
发展壮大村级集体经济是强农业、美农村、富农民的重要举措,是全面推进
2023-06-14
我个人不太喜欢在车身上使用奢华的颜色(如粉红色、紫色或绿松石色)。在
2023-06-14
来为大家解答以上问题,怎么解除qq游戏限制,如何解除qq登录限制很多人
2023-06-14
6月14日,据彭博消息,根据阿根廷经济部周二通过短信发出的声明,福特
2023-06-14
2023年06月14日盘中消息,09时45分人民网(603000)触及涨停板。目前价
2023-06-14
中信证券研报指出,2023年以来白酒动销端保持复苏节奏,符合预期,但市
2023-06-14
2023年6月13日我爱我家融资净买入8 8万元,融资余额1 86亿元
2023-06-14
纵观第一阶段比赛,有惊喜也有意外,但是正处于低谷期的中国足球,似乎
2023-06-14
1、血统决定命运黄土人是女娲的直系子孙身上有着特殊的烙印。本文分享
2023-06-14
近年来,NVIDIA在显存配置方面略显吝啬,引发了许多显卡爱好者进行自行
2023-06-14
microsoftoffice2007破解版MicrosoftOffice2007破解版是一款全新改版的微软Of
2023-06-14
1、您打开的页面有一些问题,就是脚本语言,脚本语言是一些代码。2、可
2023-06-14
对于鸵鸟政策是什么意思这个问题感兴趣的朋友应该很多,这个也是目前大
2023-06-14
南都·湾财社讯6月13日,从国家金融监督管理总局官网获悉,吉安农村商
2023-06-13
来为大家解答以上问题,硬盘温度多少正常范围,硬盘温度多少正常很多人
2023-06-13
工资数据吓崩市场!英国央行重启50个基点“暴力加息”预期升温,加息,基
2023-06-13
想必现在有很多小伙伴对于如何养兔子?方面的知识都比较想要了解,那么
2023-06-13
经济观察网记者郑淯心6月13日下午,在贵州茅台(600519 SH)的股东大会
2023-06-13
1、黄河。2、在古代,河是黄河的专有名词。3、江是长江的专有名词。4、
2023-06-13
大家好,小乐来为大家解答以上的问题。和栩栩如生意思相近的词语有什么
2023-06-13
“法治是最好的营商环境”。今年以来,西安市莲湖区司法局深入贯彻落实
2023-06-13
广汽集团A股将于6月16日派发现金红利18 87亿元,a股,刘军,广汽集团,现金
2023-06-13
中银证券:新能源汽车全球景气度持续向上全年销量有望再创历史新高:中
2023-06-13
战术 意志胜利!华科大比肩清北创纪录三点让刘禹彤25分化泡影,篮球,女
2023-06-13
荣盛发展3涨停
2023-06-13
经州火险会商研判组对近期气象因子可燃物因子、人为活动因子综合研判,
2023-06-13
在美国,大约有0 7%的商品猪在运输过程中受伤、无法行走或死亡。由猪肉
2023-06-13
创新创业创造决赛现场 供图云南网讯(记者 赵岗)6月12日,昆明市盘
2023-06-13
摘要:2023年06月13日华工科技(000988)换手率大于8%,主力资金净流出
2023-06-13
1、安徽神祥科技有限公司于2019年08月14日成立。2、法定代表人葛少华,
2023-06-13
来为大家解答以下的问题,德市烟草专卖局电话,宁德烟草网上订货这个很
2023-06-13
国产恐怖电影,一直是内陆电影市场的稀缺类型。随着近几年国内网络
2023-06-13
近日,中国人寿保险股份有限公司保费收入公告发布。公告显示,中国人寿
2023-06-13Copyright © 2015-2022 现在水产网版权所有 备案号:粤ICP备18023326号-5 联系邮箱:855 729 8@qq.com