如何做到Android Flutter自适应瀑布流
发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,今天就跟大家聊聊有关如何做到Android Flutter自适应瀑布流,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Flutter自适应瀑布流
千家信息网最后更新 2024年11月11日如何做到Android Flutter自适应瀑布流
今天就跟大家聊聊有关如何做到Android Flutter自适应瀑布流,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
Flutter自适应瀑布流
前言:在电商app经常会看到首页商品推荐的瀑布流,或者类似短视频app首页也是瀑布流,这些都是需要自适应的,才能给用户带来好的体验
话不多说先上效果图:
根据效果图可以分为四步:
图片自适应
自适应标签
上拉刷新和下拉加载
底部的点赞按钮可以去掉或者自己修改样式,我这里使用的like_button库
注:本文使用的库:为啥这么多呢,因为我把图片缓存这样东西都加上了,单纯的瀑布流就用waterfall_flow
waterfall_flow: ^3.0.1extended_image: anyextended_sliver: anyff_annotation_route_library: anyhttp_client_helper: anyintl: anylike_button: anyloading_more_list: anypull_to_refresh_notification: anyurl_launcher: any
1.图片自适应:
Widget image = Stack( children:[ ExtendedImage.network( item.imageUrl, shape: BoxShape.rectangle, //clearMemoryCacheWhenDispose: true, border: Border.all(color: Colors.grey.withOpacity(0.4), width: 1.0), borderRadius: const BorderRadius.all( Radius.circular(10.0), ), loadStateChanged: (ExtendedImageState value) { if (value.extendedImageLoadState == LoadState.loading) { Widget loadingWidget = Container( alignment: Alignment.center, color: Colors.grey.withOpacity(0.8), child: CircularProgressIndicator( strokeWidth: 2.0, valueColor: AlwaysStoppedAnimation (Theme.of(c).primaryColor), ), ); if (!konwSized) { //todo: not work in web loadingWidget = AspectRatio( aspectRatio: 1.0, child: loadingWidget, ); } return loadingWidget; } else if (value.extendedImageLoadState == LoadState.completed) { item.imageRawSize = Size( value.extendedImageInfo.image.width.toDouble(), value.extendedImageInfo.image.height.toDouble()); } return null; }, ), Positioned( top: 5.0, right: 5.0, child: Container( padding: const EdgeInsets.all(3.0), decoration: BoxDecoration( color: Colors.grey.withOpacity(0.6), border: Border.all(color: Colors.grey.withOpacity(0.4), width: 1.0), borderRadius: const BorderRadius.all( Radius.circular(5.0), ), ), child: Text( '${index + 1}', textAlign: TextAlign.center, style: const TextStyle(fontSize: fontSize, color: Colors.white), ), ), ) ],);if (konwSized) { image = AspectRatio( aspectRatio: item.imageSize.width / item.imageSize.height, child: image, ); } else if (item.imageRawSize != null) { image = AspectRatio( aspectRatio: item.imageRawSize.width / item.imageRawSize.height, child: image, ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ image, const SizedBox( height: 5.0, ), buildTagsWidget(item), const SizedBox( height: 5.0, ), buildBottomWidget(item), ], );}
2.自适应标签:
Widget buildTagsWidget( TuChongItem item, { int maxNum = 6,}) { const double fontSize = 12.0; return Wrap( runSpacing: 5.0, spacing: 5.0, children: item.tags.take(maxNum).map((String tag) { final Color color = item.tagColors[item.tags.indexOf(tag)]; return Container( padding: const EdgeInsets.all(3.0), decoration: BoxDecoration( color: color, border: Border.all(color: Colors.grey.withOpacity(0.4), width: 1.0), borderRadius: const BorderRadius.all( Radius.circular(5.0), ), ), child: Text( tag, textAlign: TextAlign.start, style: TextStyle( fontSize: fontSize, color: color.computeLuminance() < 0.5 ? Colors.white : Colors.black), ), ); }).toList());}
3.上拉刷新和下拉加载
class PullToRefreshHeader extends StatelessWidget { const PullToRefreshHeader(this.info, this.lastRefreshTime, {this.color}); final PullToRefreshScrollNotificationInfo info; final DateTime lastRefreshTime; final Color color; @override Widget build(BuildContext context) { if (info == null) { return Container(); } String text = ''; if (info.mode == RefreshIndicatorMode.armed) { text = 'Release to refresh'; } else if (info.mode == RefreshIndicatorMode.refresh || info.mode == RefreshIndicatorMode.snap) { text = 'Loading...'; } else if (info.mode == RefreshIndicatorMode.done) { text = 'Refresh completed.'; } else if (info.mode == RefreshIndicatorMode.drag) { text = 'Pull to refresh'; } else if (info.mode == RefreshIndicatorMode.canceled) { text = 'Cancel refresh'; } final TextStyle ts = const TextStyle( color: Colors.grey, ).copyWith(fontSize: 13); final double dragOffset = info?.dragOffset ?? 0.0; final DateTime time = lastRefreshTime ?? DateTime.now(); final double top = -hideHeight + dragOffset; return Container( height: dragOffset, color: color ?? Colors.transparent, //padding: EdgeInsets.only(top: dragOffset / 3), //padding: EdgeInsets.only(bottom: 5.0), child: Stack( children:[ Positioned( left: 0.0, right: 0.0, top: top, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Container( alignment: Alignment.centerRight, child: RefreshImage(top), margin: const EdgeInsets.only(right: 12.0), ), ), Column( children: [ Text( text, style: ts, ), Text( 'Last updated:' + DateFormat('yyyy-MM-dd hh:mm').format(time), style: ts.copyWith(fontSize: 12), ) ], ), Expanded( child: Container(), ), ], ), ) ], ), ); }}class RefreshImage extends StatelessWidget { const RefreshImage(this.top); final double top; @override Widget build(BuildContext context) { const double imageSize = 40; return ExtendedImage.asset( Assets.assets_fluttercandies_grey_png, width: imageSize, height: imageSize, afterPaintImage: (Canvas canvas, Rect rect, ui.Image image, Paint paint) { final double imageHeight = image.height.toDouble(); final double imageWidth = image.width.toDouble(); final Size size = rect.size; final double y = (1 - min(top / (refreshHeight - hideHeight), 1)) * imageHeight; canvas.drawImageRect( image, Rect.fromLTWH(0.0, y, imageWidth, imageHeight - y), Rect.fromLTWH(rect.left, rect.top + y / imageHeight * size.height, size.width, (imageHeight - y) / imageHeight * size.height), Paint() ..colorFilter = const ColorFilter.mode(Color(0xFFea5504), BlendMode.srcIn) ..isAntiAlias = false ..filterQuality = FilterQuality.low); //canvas.restore(); }, ); }}
4.底部的点赞按钮
LikeButton( size: 18.0, isLiked: item.isFavorite, likeCount: item.favorites, countBuilder: (int count, bool isLiked, String text) { final ColorSwatchcolor = isLiked ? Colors.pinkAccent : Colors.grey; Widget result; if (count == 0) { result = Text( 'love', style: TextStyle(color: color, fontSize: fontSize), ); } else { result = Text( count >= 1000 ? (count / 1000.0).toStringAsFixed(1) + 'k' : text, style: TextStyle(color: color, fontSize: fontSize), ); } return result; }, likeCountAnimationType: item.favorites < 1000 ? LikeCountAnimationType.part : LikeCountAnimationType.none, onTap: (bool isLiked) { return onLikeButtonTap(isLiked, item); },)
这样自适应的瀑布流就完成了。
看完上述内容,你们对如何做到Android Flutter自适应瀑布流有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。
瀑布
内容
图片
底部
按钮
效果
效果图
标签
首页
下拉
东西
前言
商品
常会
更多
样式
用户
知识
篇文章
缓存
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
cmm把软件开发组织的能力
如何抓取请求回来的数据库
欧姆龙服务器报警40
19年网络安全周
中国网络安全预算
陆陆互联网科技有限公司
数据库中包括哪些对象
wow新开服务器
网络安全创新洪流方案
博雅数据库合肥工业大学
五华区信息化软件开发厂家价格
网络安全大赛门票
霏凡软件开发者
为什么软件开发商要强制推送消息
优炫数据库邀请函
it软件开发技术方案书
医院网络安全排查整治情况
祥利科技工业互联网
福州康为网络技术有限公司官网
滨江区学习软件开发
广东上门软件开发资格
固定服务器角色管理
wow新开服务器
到哪里学会网络技术
环球黑卡 谛听网络技术
软件开发的201个原则 百度
软件开发属于施工吗
idea中打开数据库文件
网络技术安全激励措施
网络安全协议及安全问题