陕西住房城乡住房建设厅网站合肥瑶海区网站建设费用

web/2025/10/5 11:50:18/文章来源:
陕西住房城乡住房建设厅网站,合肥瑶海区网站建设费用,湖北住房城乡建设厅网站,wordpress视频教程 百度云03_Flutter自定义下拉菜单 在Flutter的内置api中#xff0c;可以使用showMenu实现类似下拉菜单的效果#xff0c;或者使用PopupMenuButton组件#xff0c;PopupMenuButton内部也是使用了showMenu这个api#xff0c;但是使用showMenu时#xff0c;下拉面板的显示已经被约定… 03_Flutter自定义下拉菜单 在Flutter的内置api中可以使用showMenu实现类似下拉菜单的效果或者使用PopupMenuButton组件PopupMenuButton内部也是使用了showMenu这个api但是使用showMenu时下拉面板的显示已经被约定死了只能放一个简单的列表没有办法定制下来面板的ui并且下拉面板的宽高需要通过指定constraints进行限制下面是一个简单的showMenu的用法: Container(height: 44,margin: EdgeInsetsDirectional.only(top: 30, start: 30, end: 30),color: Colors.red,child: Builder(builder: (context) {return GestureDetector(onTap: () {final RenderBox button context.findRenderObject()! as RenderBox;final RenderBox overlay Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox;Offset offset Offset(0.0, button.size.height);RelativeRect position RelativeRect.fromRect(Rect.fromPoints(button.localToGlobal(offset, ancestor: overlay),button.localToGlobal(button.size.bottomRight(Offset.zero) offset, ancestor: overlay),),Offset.zero overlay.size,);showMenu(context: context,position: position,constraints: BoxConstraints(maxWidth: 315, maxHeight: 200),items: List.generate(5, (index) PopupMenuItem(child: Container(width: 375,height: 44,alignment: AlignmentDirectional.center,child: Text(item),))));},);},), )接下来我们将参照showMenu的源码依葫芦画个瓢自定义一个下拉菜单的api并可自由定制下拉面板的布局内容篇幅有点长请耐心观看。 一.确定下拉面板的起始位置 查看PopupMenuButton的源码可以知道PopupMenuButton在确定下拉面板的起始位置时是先获取下拉面板依赖的按钮的边界位置和整个页面的显示区域边界通过这两个边界计算得到一个RelativeRect这个RelativeRect就是用来描述下拉面板的起始位置的。 showPopup(BuildContext context) {final RenderBox button context.findRenderObject()! as RenderBox;final RenderBox overlay Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox;Offset offset Offset(0.0, button.size.height);RelativeRect position RelativeRect.fromRect(Rect.fromPoints(button.localToGlobal(offset, ancestor: overlay),button.localToGlobal(button.size.bottomRight(Offset.zero) offset, ancestor: overlay),),Offset.zero overlay.size,); }注上述代码中用的的context对象必须是下拉面板依赖的按钮对应的context否则最后计算出来的RelativeRect是不对的。计算过程不做过多解释了直接上图 二.确定下拉面板的布局约束 水平方向确定最大宽度比较简单下拉面板的最大宽度和它所依赖的按钮的宽度一致即可垂直方向上的最大高度上一步已经确定了position的值垂直方向上的最大高度可以取position.top - buttonHeight - padding.top - kToolbarHeight和constraints.biggest.height - position.top - padding.bottom的最大值padding为安全区域的大小使用CustomSingleChildLayout作为下拉面板的父容器并实现一个SingleChildLayoutDelegate重写getConstraintsForChild确定约束 EdgeInsets padding MediaQuery.paddingOf(context);class _CustomPopupRouteLayout extends SingleChildLayoutDelegate {final RelativeRect position;_CustomPopupRouteLayout(this.position);overrideBoxConstraints getConstraintsForChild(BoxConstraints constraints) {Size buttonSize position.toSize(constraints.biggest);double constraintsWidth buttonSize.width;double constraintsHeight max(position.top - buttonSize.height - padding.top - kToolbarHeight, constraints.biggest.height - position.top - padding.bottom);return BoxConstraints.loose(Size(constraintsWidth, constraintsHeight));}overridebool shouldRelayout(covariant _CustomPopupRouteLayout oldDelegate) {return position ! oldDelegate.position;} }三.显示下拉面板 我们先把下拉面板显示出来看看效果这里的下拉面板其实是一个弹出层而在Flutter中所有的弹出层的显示和页面路由是一样的都是通过Navigator.push进行显示参照showMenu的源码这里的弹出层我们让其继承PopupRoute class _CustomPopupRouteT extends PopupRouteT {final RelativeRect position;overridefinal String? barrierLabel;_CustomPopupRoute({required this.position,required this.barrierLabel,});overrideColor? get barrierColor null;overridebool get barrierDismissible true;overrideDuration get transitionDuration Duration(milliseconds: 200);overrideWidget buildPage(BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation) {return CustomSingleChildLayout(delegate: _CustomPopupRouteLayout(position),child: Material(child: Container(color: Colors.yellow,width: double.infinity,height: double.infinity,alignment: AlignmentDirectional.center,child: Text(popup content),),),);}}showPopup(BuildContext context) {final RenderBox button context.findRenderObject()! as RenderBox;final RenderBox overlay Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox;Offset offset Offset(0.0, button.size.height);RelativeRect position RelativeRect.fromRect(Rect.fromPoints(button.localToGlobal(offset, ancestor: overlay),button.localToGlobal(button.size.bottomRight(Offset.zero) offset, ancestor: overlay),),Offset.zero overlay.size,);Navigator.of(context).push(_CustomPopupRoute(position: position, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel)); }如图黄色区域就是下拉面板可以看到点击按钮下拉面板显示点击下拉面板以外的区域下拉面板关闭但是位置好像不对因为我们根本就没去确定下拉面板的位置。 四.确定下拉面板的位置 override Offset getPositionForChild(Size size, Size childSize) {return super.getPositionForChild(size, childSize); }只需要重写SingleChildLayoutDelegate的getPositionForChild方法返回一个Offset对象Offset的x、y的值就代表下拉面板左上角的位置那么问题来了x、y的值怎么确定 确定x x position.left 确定y position.top constraintsHeight size.height - paddingBottom 时 position.top constraintsHeight size.height - paddingBottom 时 EdgeInsets padding MediaQuery.paddingOf(context);class _CustomPopupRouteLayout extends SingleChildLayoutDelegate {final RelativeRect position;EdgeInsets padding;_CustomPopupRouteLayout(this.position, this.padding);overrideBoxConstraints getConstraintsForChild(BoxConstraints constraints) {Size buttonSize position.toSize(constraints.biggest);double constraintsWidth buttonSize.width;double constraintsHeight max(position.top - buttonSize.height - padding.top - kToolbarHeight, constraints.biggest.height - position.top - padding.bottom);return BoxConstraints.loose(Size(constraintsWidth, constraintsHeight));}overrideOffset getPositionForChild(Size size, Size childSize) {double x position.left;double y position.top;final double buttonHeight size.height - position.top - position.bottom;double constraintsHeight max(position.top - buttonHeight - padding.top - kToolbarHeight, size.height - position.top - padding.bottom);if(position.top constraintsHeight size.height - padding.bottom) {y position.top - childSize.height - buttonHeight;}return Offset(x, y);}overridebool shouldRelayout(covariant _CustomPopupRouteLayout oldDelegate) {return position ! oldDelegate.position || padding ! oldDelegate.padding;} }六.下拉动画实现 创建动画插值器其值从0 ~ 1之间变化动画时长为PopupRoute中重写的transitionDuration及200ms时间内从0变到1或者从1变到0 final CurveTween heightFactorTween CurveTween(curve: const Interval(0.0, 1.0));使用AnimatedBuilder改造PopupRoute的布局结构根据heightFactorTween的动画执行值 * 下拉菜单内容容器的高度改变拉菜单内容的高度即可这里暂时将高度设置为固定值300。 class _CustomPopupRouteT extends PopupRouteT {...overrideWidget buildPage(BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation) {EdgeInsets padding MediaQuery.paddingOf(context);final CurveTween heightFactorTween CurveTween(curve: const Interval(0.0, 1.0));return MediaQuery.removePadding(context: context,removeTop: true,removeBottom: true,removeLeft: true,removeRight: true,child: CustomSingleChildLayout(delegate: _CustomPopupRouteLayout(position, padding),child: AnimatedBuilder(animation: animation,builder: (context, child) {return Material(child: Container(height: 300*heightFactorTween.evaluate(animation),child: child,));},child: Container(color: Colors.yellow,width: double.infinity,height: 300,alignment: AlignmentDirectional.center,child: Text(popup content),),),),);} }下拉动画效果已经出来了但是实际情况下下拉面板的高度是不能直接在组件层固定写死的所以这里需要动态计算出下拉面板的高度。 七.下拉面板动态高度支持下拉动画 想要获取组件的高度需要等到组件的layout完成后才能获取到组件的大小因此我们需要自定义一个RenderObject重写其performLayout在子控件第一次layout完后获取到子控件的初始高度子控件的初始化高度结合动画的高度比例系数来最终确定自身的大小。 class _RenderHeightFactorBox extends RenderShiftedBox {double _heightFactor;_RenderHeightFactorBox({RenderBox? child,double? heightFactor,}):_heightFactor heightFactor ?? 1.0, super(child);double get heightFactor _heightFactor;set heightFactor(double value) {if (_heightFactor value) {return;}_heightFactor value;markNeedsLayout();}overridevoid performLayout() {final BoxConstraints constraints this.constraints;if (child null) {size constraints.constrain(Size.zero);return;}child!.layout(constraints, parentUsesSize: true);size constraints.constrain(Size(child!.size.width,child!.size.height,));child!.layout(constraints.copyWith(maxWidth: size.width, maxHeight: size.height * heightFactor), parentUsesSize: true);size constraints.constrain(Size(child!.size.width,child!.size.height,));} }接着定义一个SingleChildRenderObjectWidget并引用_RenderHeightFactorBox class _HeightFactorBox extends SingleChildRenderObjectWidget {final double? heightFactor;const _HeightFactorBox({super.key,this.heightFactor,super.child,});overrideRenderObject createRenderObject(BuildContext context) _RenderHeightFactorBox(heightFactor: heightFactor);overridevoid updateRenderObject(BuildContext context, _RenderHeightFactorBox renderObject) {renderObject.heightFactor heightFactor ?? 1.0;} }最后把下拉面板中执行动画的child使用_HeightFactorBox包裹并传入heightFactorTween的执行结果即可。 override Widget buildPage(BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation) {EdgeInsets padding MediaQuery.paddingOf(context);final CurveTween heightFactorTween CurveTween(curve: const Interval(0.0, 1.0));return MediaQuery.removePadding(context: context,removeTop: true,removeBottom: true,removeLeft: true,removeRight: true,child: CustomSingleChildLayout(delegate: _CustomPopupRouteLayout(position, padding),child: AnimatedBuilder(animation: animation,builder: (context, child) {return Material(child: _HeightFactorBox(heightFactor: heightFactorTween.evaluate(animation),child: child,));},child: Container(color: Colors.yellow,width: double.infinity,height: double.infinity,alignment: AlignmentDirectional.center,child: Text(popup content),),),),); }八.完整代码 class TestPage extends StatelessWidget {overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(下拉菜单),backgroundColor: Colors.blue,),body: Container(width: 375,child: Column(mainAxisSize: MainAxisSize.max,mainAxisAlignment: MainAxisAlignment.spaceBetween,crossAxisAlignment: CrossAxisAlignment.center,children: [Container(height: 44,margin: const EdgeInsetsDirectional.only(top: 30, start: 30, end: 30),color: Colors.red,child: Builder(builder: (context) {return GestureDetector(onTap: () {showPopup(context: context, builder: (context) {return Container(height: 400,decoration: const BoxDecoration(color: Colors.yellow),child: SingleChildScrollView(physics: const ClampingScrollPhysics(),child: Column(mainAxisSize: MainAxisSize.max,mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.stretch,children: ListWidget.generate(29, (index) {int itemIndex index ~/ 2;if(index.isEven) {return Container(height: 44,alignment: AlignmentDirectional.center,child: Text(item$itemIndex),);} else {return Container(height: 1,color: Colors.grey,);}}),),),);});},);},),),],),),);}}showPopup({required BuildContext context,required WidgetBuilder builder,double? elevation,Color? shadowColor,Duration animationDuration const Duration(milliseconds: 200) }) {final RenderBox button context.findRenderObject()! as RenderBox;final RenderBox overlay Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox;Offset offset Offset(0.0, button.size.height);RelativeRect position RelativeRect.fromRect(Rect.fromPoints(button.localToGlobal(offset, ancestor: overlay),button.localToGlobal(button.size.bottomRight(Offset.zero) offset, ancestor: overlay),),Offset.zero overlay.size,);Navigator.of(context).push(_CustomPopupRoute(position: position,builder: builder,elevation: elevation,shadowColor: shadowColor,animationDuration: animationDuration,barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel)); }class _CustomPopupRouteT extends PopupRouteT {final WidgetBuilder builder;final RelativeRect position;final double? elevation;final Color? shadowColor;overridefinal String? barrierLabel;final Duration animationDuration;_CustomPopupRoute({required this.builder,required this.position,required this.barrierLabel,this.elevation,this.shadowColor,Duration? animationDuration}): animationDuration animationDuration ?? const Duration(milliseconds: 200),super(traversalEdgeBehavior: TraversalEdgeBehavior.closedLoop);overrideColor? get barrierColor null;overridebool get barrierDismissible true;overrideDuration get transitionDuration animationDuration;overrideWidget buildPage(BuildContext context, Animationdouble animation, Animationdouble secondaryAnimation) {EdgeInsets padding MediaQuery.paddingOf(context);final CurveTween heightFactorTween CurveTween(curve: const Interval(0.0, 1.0));return MediaQuery.removePadding(context: context,removeTop: true,removeBottom: true,removeLeft: true,removeRight: true,child: CustomSingleChildLayout(delegate: _CustomPopupRouteLayout(position, padding),child: AnimatedBuilder(animation: animation,builder: (context, child) {return Material(child: _HeightFactorBox(heightFactor: heightFactorTween.evaluate(animation),child: child,));},child: builder(context),),),);}}class _CustomPopupRouteLayout extends SingleChildLayoutDelegate {final RelativeRect position;EdgeInsets padding;double childHeightMax 0;_CustomPopupRouteLayout(this.position, this.padding);overrideBoxConstraints getConstraintsForChild(BoxConstraints constraints) {Size buttonSize position.toSize(constraints.biggest);double constraintsWidth buttonSize.width;double constraintsHeight max(position.top - buttonSize.height - padding.top - kToolbarHeight, constraints.biggest.height - position.top - padding.bottom);return BoxConstraints.loose(Size(constraintsWidth, constraintsHeight));}overrideOffset getPositionForChild(Size size, Size childSize) {double x position.left;double y position.top;final double buttonHeight size.height - position.top - position.bottom;double constraintsHeight max(position.top - buttonHeight - padding.top - kToolbarHeight, size.height - position.top - padding.bottom);if(position.top constraintsHeight size.height - padding.bottom) {y position.top - childSize.height - buttonHeight;}return Offset(x, y);}overridebool shouldRelayout(covariant _CustomPopupRouteLayout oldDelegate) {return position ! oldDelegate.position || padding ! oldDelegate.padding;} }class _RenderHeightFactorBox extends RenderShiftedBox {double _heightFactor;_RenderHeightFactorBox({RenderBox? child,double? heightFactor,}):_heightFactor heightFactor ?? 1.0, super(child);double get heightFactor _heightFactor;set heightFactor(double value) {if (_heightFactor value) {return;}_heightFactor value;markNeedsLayout();}overridevoid performLayout() {final BoxConstraints constraints this.constraints;if (child null) {size constraints.constrain(Size.zero);return;}child!.layout(constraints, parentUsesSize: true);size constraints.constrain(Size(child!.size.width,child!.size.height,));child!.layout(constraints.copyWith(maxWidth: size.width, maxHeight: size.height * heightFactor), parentUsesSize: true);size constraints.constrain(Size(child!.size.width,child!.size.height,));} }class _HeightFactorBox extends SingleChildRenderObjectWidget {final double? heightFactor;const _HeightFactorBox({super.key,this.heightFactor,super.child,});overrideRenderObject createRenderObject(BuildContext context) _RenderHeightFactorBox(heightFactor: heightFactor);overridevoid updateRenderObject(BuildContext context, _RenderHeightFactorBox renderObject) {renderObject.heightFactor heightFactor ?? 1.0;} }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

专业网站优化服务找公司开发网站

UML视频一直在看,但是总觉得没有什么思路,知识都是零散的、片面的。最后复习阶段老师重新理了一下思路,我才觉得有点清晰了。所以,又回头把UML概述部分总结了一下。 感慨一句:思维导图真的要勤画,画图也是在…

地推网站信息怎么做阿芹网站建设

背景动手学 docker最近,终于完成了 动手学 docker 系列的编写。动手学 docker 是 动手学系列 的首个系列。如果反馈的效果不错,后续还将推出 动手学 devops动手学 kubernetes动手学 istio 等系列。动手学系列 的构思来源于 李沐 老师的 动手学深度学习 。…

具有价值的建网站网站开发需要自己写代码吗

背景: 我做了一个简单的库,负责与数据库交互,希望能兼容数据库类型多一些。偶然想试试access,结果调试出错了。特此记录下来。 原因: windows中的odbc中,预制了很多基础的数据库驱动,这在200…

seo网站排名厂商定制个人做公司网站

1517 求一次函数解析式 时间限制: 1 s空间限制: 128000 KB题目等级 : 白银 Silver题解查看运行结果题目描述 Description相信大家都做过练习册上的这种 题吧: 已知一个一次函数的图像经过点(x1,y1)、(x2,y2),求该函数的…

微信官方网站登陆wordpress静态生成

12 4 3,这个关系表达式叫作除法算式,表述为 12 除以 4 等于 3;也可以表述为 4 除 12 等于 3。

宝安建网站的公司临川区建设局网站

51单片机学习笔记14 LCD1602显示屏使用 一、LCD1602介绍1. 简介2. 引脚定义3. DDRAM4. 字模5. 指令(1)清屏指令 0x01(2)光标归位指令 0x02(3)进入模式设置指令 0x06(4)显示开关控制指…

网站程序开发公司北京公司网站设计价格

在网上看来很多关于同步锁的博文,记录下来方便以后阅读 一、Lock和synchronized有以下几点不同: 1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面…

网店交易平台网站建设青海网站建设公司

集合简介 概念:对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能。和数组的区别: 数组长度固定,集合长度不固定。数组可以存储基本类型和引用类型,集合只能存储引用类型。 位置: jav…

实用设计网站推荐无货源开店已确认违法

我已经开始修改自定义Java二进制运行时映像文件。 映像文件是打包为运行时平台的模块的配置。 基本上,默认映像包含组成Java运行时的所有内容。 自定义图像可以包含该图像的一些子集。 例如,我创建了一个仅包含“ compact 3”概要文件的映像&#xff0c…

国外网站页面做多大不用模板怎么建设网站

接口测试 新增接口脚本编写和执行测试,并执行脚本。 (1)商品单位添加接口描述如下: 接口功能:提供商品单位新增处理。 接口地址(根据实际系统IP及端口自行替换): http://XX.XX.XX.XX:XXXX/prod-api/manager/category/add。 请求方式:POST。 请求参数:

青海建设厅网站通知代理加盟做什么好

课程介绍 学习地址 《Stable Diffusion商业级玩法》通过详细讲解AI绘画技巧、实操演示和个性化指导,帮助您从零基础成为绘画高手,帮助您有效推广产品或服务,提升市场份额。教您掌握稳定扩散绘画技巧,开启艺术创作新篇章。

网站建设方案 doc优秀网站介绍

server {listen 80;server_name example.com;location / {proxy_pass http://backend;}location / 是 Nginx 的一个匹配规则,用于匹配所有请求路径。proxy_pass 指令则用于将匹配到的请求转发给指定的后端服务器。下面是关于 location / 和 proxy_pass 的详细介绍&a…

上海网站备案多久网站ip段屏蔽

很多设计模式看起来或者感觉上差不多,其实不仅仅要从具体的实现方式来辨别,更要主要该种设计模式的意图。 那些容易混淆的设计模式,了解一下~_看了几种设计模式发现有点混乱,都差不多啊-CSDN博客

开一家网站建设公司有前景吗找项目网站

今天,我不得不准备一些示例来说明Web服务是可互操作的。 因此,我已经使用Metro使用Java创建了一个简单的Web服务,并在Tomcat上启动了它。 然后尝试使用Python和Ruby消耗它们。 这是全部完成的过程… Java中的Web服务 我从Java中的简单Web服…

wordpress 基础seo建站东莞在哪里学网站建设

我有个朋友之前在唯品会开的店,现在想转战其他平台,想要店铺信息商品信息全部迁移过去,如果想要人工手动操作就有点麻烦了,然后有天找到我 ,让我看看能不能通过技术手段实现商品信息迁移。嫌来无事,写了下面…

四川微信网站建设推品牌建设归哪个部门管

文章目录 [toc]1. GW1NSR-4C串口外设简介2. FPGA配置3. 常用函数4. 轮询方式接收数据5. 中断方式接收数据 本文是高云FPGA系列教程的第8篇文章。 本篇文章介绍片上ARM Cortex-M3硬核处理器串口外设的使用,演示轮询方式和中断方式接收串口数据,并进行回环…

网站安全设计网站开发前端需要学什么

时代漫画07.PDF: https://url03.ctfile.com/f/1779803-1247458105-0a2c41?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了,截止1937年6月战争来临被迫停刊共发行了39期。 ps:资源来源网络!

搭建三合一网站手机网站的内容模块

点击蓝字关注我们C11 中增加了许多的新特性。在本文中,我们来聊一下 lambda 表达式,闭包,std::function以及std::bind。lambda 表达式C11 中新增了 lambda 表达式这一语言特性。lambda 表达式可以让我们快速和便捷的创建一个 “函数”。下面是…

中国国家城乡建设部网站直接用源码做网站盗版吗

写程序员简历时,可以从以下几个方面入手: 1. 个人信息:在简历的开头,包含个人基本信息如姓名、联系方式、地址等。 2. 求职目标/职业目标:明确自己希望得到的职位或行业,并简要描述为什么适合该职位。 3…

济宁梵盛科技网站建设西安做网站的公司

目录 构建生态系统 将Arm架构小芯片带给大众 关于Arm Total Design的结语 我们最近报道了Arm的Neoverse CSS Genesis N2平台的发布,这是一个近乎现成的计算子系统设计,旨在加快尖端基础设施中定制加速器的上市时间。我们当时评论说,我们可…