购物网站排版设计,本科自考和专升本的区别,宣传旅游网站建设的观点是什么,企业网站的推广阶段和特点前置知识点学习
GlobalKey
GlobalKey 是 Flutter 中一个非常重要的概念#xff0c;它用于唯一标识 widget 树中的特定 widget#xff0c;并提供对该 widget 的访问。这在需要跨越 widget 树边界进行交互或在 widget 树重建时保持状态时尤其有用。
GlobalKey 的作用
唯一标…前置知识点学习
GlobalKey
GlobalKey 是 Flutter 中一个非常重要的概念它用于唯一标识 widget 树中的特定 widget并提供对该 widget 的访问。这在需要跨越 widget 树边界进行交互或在 widget 树重建时保持状态时尤其有用。
GlobalKey 的作用
唯一标识GlobalKey 可以在 widget 树中唯一标识一个 widget 实例。这在需要在多个地方引用同一个 widget 时特别有用。访问状态可以通过 GlobalKey 访问 StatefulWidget 的状态对象。这允许你在 widget 树之外操作该 widget 的状态。在重建时保持状态当 widget 树重建时GlobalKey 可以确保与该 key 关联的 widget 保持其状态不变。通常情况下Flutter 会根据位置和类型重新创建 widget但使用 GlobalKey 可以避免这种情况。 跨越 widget 树边界的操作可以用于在 widget 树的一个部分与另一个部分之间传递信息或触发操作这在复杂的 UI 中非常有用。 GlobalKey 案例
import package:flutter/material.dart;class MyGlobalKeyPage extends StatelessWidget {MyGlobalKeyPage({super.key});final GlobalKey_MySimpleWidgetState _key GlobalKey_MySimpleWidgetState();overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(MyBubbleDemoPage),),body: Container(width: MediaQuery.sizeOf(context).width,height: MediaQuery.sizeOf(context).height,margin: const EdgeInsets.all(15),child: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [MySimpleWidget(key: _key),ElevatedButton(onPressed: () {// 閫氳繃 GlobalKey 璁块棶 MyWidget 鐨勭姸鎬侊紝骞惰皟鐢ㄥ叾鏂规硶_key.currentState?.changeText();},child: Text(Call Method on MySimpleWidget),),],),),));}
}class MySimpleWidget extends StatefulWidget {const MySimpleWidget({super.key});override_MySimpleWidgetState createState() {return _MySimpleWidgetState();}
}class _MySimpleWidgetState extends StateMySimpleWidget {String _text Hello GlobalKey;overrideWidget build(BuildContext context) {return Text(_text);}void changeText() {setState(() {_text Hello TEXT has changed;});
GlobalKey在示例中的作用
标识和访问GlobalKey 用于标识 MySimpleWidget 实例并通过 _key.currentState 访问其状态和方法。跨 widget 树操作通过 ElevatedButton我们可以从 MyGlobalKeyPage 中访问并操作 MySimpleWidget 的状态。
注意事项
唯一性GlobalKey 必须在 widget 树中唯一使用。多个 widget 共享同一个 GlobalKey 会导致异常。性能开销由于 GlobalKey 会阻止 widget 的优化重建过多使用可能影响性能。应在必要时使用。避免滥用虽然 GlobalKey 很强大但应尽量在局部范围内使用避免在整个应用中广泛使用。
通过正确使用 GlobalKey你可以在 Flutter 应用中实现更复杂的状态管理和交互逻辑。它为在 widget 树结构中实现灵活的组件通信提供了强有力的支持。 flutter报错
Cant define the const constructor because the field _key is initialized with a non-constant value.
这个错误信息是因为在 Flutter 中你试图在一个 const 构造函数中初始化一个字段而这个字段被赋予了一个非常量的值。 问题原因
在 Flutter 中const 构造函数要求所有字段都用常量值初始化。GlobalKey 和其他类似的对象在 Dart 中不是常量因为它们在运行时创建并分配内存。因此它们不能在 const 构造函数中被用作初始值。 解决方案
要解决这个问题你需要确保在构造函数中不要将 GlobalKey 或其他运行时生成的对象用于 const 构造函数。通常的做法是将这些对象作为普通的变量而不是在 const 构造函数中初始化。 示例修正
假设有以下代码导致了这个错误
class MyWidget extends StatelessWidget {final GlobalKey _key GlobalKey(); // 这里不能使用 constconst MyWidget({Key? key}) : super(key: key); // 错误的用法
}
可以通过以下方式修正 class MyWidget extends StatelessWidget {final GlobalKey _key GlobalKey(); // 不使用 constMyWidget({Key? key}) : super(key: key); // 修改为非 const 构造函数
}
或者如果你确实需要 MyWidget 是一个常量构造函数你需要移除 GlobalKey 的初始化
class MyWidget extends StatelessWidget {final GlobalKey _key;const MyWidget({Key? key, required GlobalKey keyParam}): _key keyParam, // 通过参数传递而不是初始化super(key: key);
}
然后在使用 MyWidget 时传递一个 GlobalKey 实例
final myKey GlobalKey();MyWidget(key: myKey, keyParam: myKey);
总结
const 构造函数中的字段必须是常量确保所有字段初始化都是常量表达式。
GlobalKey 不能是常量因为它们在运行时创建所以不能在 const 构造函数中直接初始化。
通过参数传递可变对象如果需要使用 const 构造函数可以通过参数将 GlobalKey 传递进去而不是在类内部直接初始化。 常量构造函数
在 Flutter 中构造函数用于初始化类的实例。const MyWidget({Key? key}) : super(key: key); 是一个常量构造函数的示例用于初始化 MyWidget 类的实例。让我们逐步解析这个构造函数的含义
const 关键字
常量构造函数使用 const 关键字定义的构造函数称为常量构造函数。它允许在编译时创建不可变的常量实例。优化在使用常量构造函数初始化的对象时如果这些对象的所有字段都是常量Flutter 可以在编译时对这些对象进行优化以减少内存使用和提高性能。
MyWidget({Key? key})
命名构造函数MyWidget 是类的构造函数。括号中的 {Key? key} 是一个可选的命名参数。Key 参数Key 是 Flutter 中用来标识 widget 的唯一标识符用于在 widget 树更新时保持 widget 的状态。Key? 表示这个参数是可选的并且可以为 null。
: super(key: key)
初始化列表冒号 : 后面的是初始化列表用于在构造函数体执行之前初始化父类的字段。super(key: key)调用父类StatelessWidget 或 StatefulWidget的构造函数并传递 key 参数。这是因为 StatelessWidget 和 StatefulWidget 的父类 Widget 定义了一个 key 参数用于管理 widget 的标识。 SingleTickerProviderStateMixin
SingleTickerProviderStateMixin 是 Flutter 中提供的一种混合mixin用于创建动画时管理 Ticker 的生命周期。它通常与 StatefulWidget 一起使用以有效地处理动画帧。
什么是 Ticker
在 Flutter 中Ticker 是一个触发动画的计时器每帧都会调用一次回调函数。它类似于一个心跳信号让动画在每个屏幕刷新周期内前进一小步。
SingleTickerProviderStateMixin 的作用
管理 TickerSingleTickerProviderStateMixin 使 State 类成为一个 TickerProvider这意味着它能够提供 Ticker 对象。这个 Ticker 用于驱动动画。
高效地管理资源通过提供一个 TickerSingleTickerProviderStateMixin 帮助确保动画在不需要时被正确地停止和释放资源。
简单便捷使用这个 mixin可以轻松创建一个 AnimationController而不需要手动管理 Ticker 的生命周期。
使用场景
通常在需要创建动画时你会在 StatefulWidget 的 State 类中使用它。以下是一个基本的使用示例
import package:flutter/material.dart;class MyAnimateWidgetPage extends StatelessWidget {overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(MyBubbleDemoPage),),body: Container(width: MediaQuery.sizeOf(context).width,height: MediaQuery.sizeOf(context).height,margin: const EdgeInsets.all(15),child: const MyAnimateWidget(),));}
}class MyAnimateWidget extends StatefulWidget {const MyAnimateWidget({super.key});override_MyAnimateWidgetState createState() _MyAnimateWidgetState();
}class _MyAnimateWidgetState extends StateMyAnimateWidgetwith SingleTickerProviderStateMixin {late AnimationController _controller;overrideWidget build(BuildContext context) {return Container(child: Center(child: FadeTransition(opacity: _controller,child: const FlutterLogo(size: 100.0),),),);}overridevoid initState() {super.initState();//vsync: this 需要一个 TickerProvider这里就是 SingleTickerProviderStateMixin 提供的_controller AnimationController(vsync: this, duration: const Duration(seconds: 2));_controller.repeat(reverse: true);}overridevoid dispose() {// 记得在 dispose 方法中释放 AnimationController_controller.dispose();super.dispose();}
}代码解析
with SingleTickerProviderStateMixin将 SingleTickerProviderStateMixin 添加到 State 类中使其成为一个 TickerProvider。
vsync: this在创建 AnimationController 时vsync 参数需要一个 TickerProvider。这里通过 this 传递当前 State 实例。
_controller.repeat(reverse: true)启动动画控制器使动画在两秒钟内从开始到结束然后反向重复。
dispose 方法在组件销毁时调用 _controller.dispose() 释放资源防止内存泄漏。
SingleTickerProviderStateMixin 是一个便捷的工具用于在 Flutter 中实现动画。它让 State 类能够提供 Ticker从而驱动动画控制器。通过这种方式你可以轻松地创建高效且可管理的动画效果。对于需要多个 Ticker 的复杂场景可以考虑使用 TickerProviderStateMixin。 MediaQuery.sizeOf(context)
MediaQuery.sizeOf(context) 是在 Flutter 中用于获取当前屏幕或父 widget 可用空间大小的一个方法。这是 Flutter 3.7 引入的一个静态方法用于简化对 MediaQuery 的访问。
用途
获取屏幕尺寸它返回一个 Size 对象包含当前设备屏幕的宽度和高度。
适配布局在构建响应式布局时可以使用这个方法来获取屏幕尺寸并调整 widget 的大小和位置。 工作原理
BuildContext它是 MediaQuery 用于查找 widget 树中与之关联的 MediaQueryData 对象的上下文。
MediaQuery.sizeOf(context)该方法通过 BuildContext 获取 MediaQueryData然后从中提取屏幕尺寸信息。 使用示例
import package:flutter/material.dart;class MyResponsiveWidgetPage extends StatelessWidget {const MyResponsiveWidgetPage({super.key});overrideWidget build(BuildContext context) {// 使用 MediaQuery.sizeOf(context) 获取屏幕尺寸Size screenSize MediaQuery.sizeOf(context);return Scaffold(appBar: AppBar(title: Text(Responsive Example)),body: Center(child: Container(width: screenSize.width * 0.8, // 宽度是屏幕宽度的 80%height: screenSize.height * 0.5, // 高度是屏幕高度的 50%color: Colors.blue,child: Center(child: Text(Responsive Container,style: TextStyle(color: Colors.white, fontSize: 20),),),),),);}
}注意事项
BuildContext 的位置MediaQuery.sizeOf(context) 所用的 context 必须是 widget 树中包含 MediaQuery 的上下文。通常这意味着它是在 MaterialApp 或 CupertinoApp 的子级中。响应式设计虽然可以简单地使用这个方法来适配屏幕大小但在复杂的布局中考虑使用其他响应式设计工具如 LayoutBuilder 或 FractionallySizedBox以更好地适配各种屏幕尺寸。更新请确保你的 Flutter SDK 版本支持 MediaQuery.sizeOf(context)因为这是一种相对较新的方法。
通过使用 MediaQuery.sizeOf(context)你可以轻松地访问设备的屏幕尺寸信息从而为用户提供更好的响应式界面布局。
import package:flutter/material.dart;class MyResponsiveWidgetPage extends StatelessWidget {const MyResponsiveWidgetPage({super.key});overrideWidget build(BuildContext context) {// 使用 MediaQuery.sizeOf(context) 获取屏幕尺寸Size screenSize MediaQuery.sizeOf(context);return Scaffold(appBar: AppBar(title: Text(Responsive Example)),body: Center(child: Container(width: screenSize.width * 0.8, // 宽度是屏幕宽度的 80%height: screenSize.height * 0.5, // 高度是屏幕高度的 50%color: Colors.blue,child: Center(child: Text(Responsive Container,style: TextStyle(color: Colors.white, fontSize: 20),),),),),);}
}GestureDetector
GestureDetector 是 Flutter 中一个非常重要的组件用于检测用户在设备屏幕上的手势。它提供了一种简单的方法来监听并响应用户的触摸、拖动、点击等交互事件。
主要功能
GestureDetector 提供了一系列回调函数允许你处理不同类型的手势。以下是一些常见的手势和对应的回调
点击手势
onTap: 用户轻触屏幕时触发。
onDoubleTap: 用户快速连续点击两次时触发。
onLongPress: 用户长按屏幕时触发。 拖动手势
onPanStart: 用户开始拖动时触发。onPanUpdate: 用户拖动时持续触发。
onPanEnd: 用户拖动结束时触发。 缩放手势
onScaleStart: 缩放手势开始时触发。
onScaleUpdate: 缩放手势更新时持续触发。
onScaleEnd: 缩放手势结束时触发。 其他手势
onVerticalDragStart, onVerticalDragUpdate, onVerticalDragEnd: 垂直拖动相关的手势。
onHorizontalDragStart, onHorizontalDragUpdate, onHorizontalDragEnd: 水平拖动相关的手势。 使用示例
import package:flutter/material.dart;class GestureExamplePage extends StatelessWidget {const GestureExamplePage({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(GestureDetector Example)),body: Center(child: GestureDetector(onTap: () {print(Container tapped!);},onPanUpdate: (details) {print(Dragging: ${details.localPosition});},child: Container(width: 200,height: 200,color: Colors.blue,child: Center(child: Text(Tap or drag me!,style: TextStyle(color: Colors.white, fontSize: 16)),),),),),);}
}细节与注意事项
透明度GestureDetector 默认只会在非透明的地方响应手势。如果你需要在透明区域也检测手势可以设置 behavior: HitTestBehavior.translucent。优先级如果多个手势检测器重叠Flutter 会根据其内部的手势识别器机制来确定哪个手势优先处理。组合手势GestureDetector 可以同时检测多个手势例如你可以同时监听 onTap 和 onDoubleTap但需要注意可能的冲突。性能在复杂的布局中需要注意手势检测的性能开销。尽量在需要的地方使用 GestureDetector避免过多的嵌套。默认行为GestureDetector 不会改变子组件的外观或行为它仅提供手势识别能力你需要在回调函数中定义具体行为。
通过 GestureDetectorFlutter 开发者可以轻松实现与用户的交互处理各种复杂的手势需求从而增强应用的用户体验。 onPanUpdate
onPanUpdate 是 GestureDetector 组件中的一个回调用于处理用户的拖动或平移手势。当用户在屏幕上拖动时onPanUpdate 会持续触发并提供有关拖动事件的信息。
主要特性
持续触发当用户在屏幕上拖动时每次移动都会触发 onPanUpdate这使得你可以跟踪拖动路径的每一个点。
事件细节回调函数接收一个 DragUpdateDetails 对象它包含有关拖动的详细信息。
DragUpdateDetails 的重要属性
globalPosition用户触摸点相对于整个屏幕的坐标。
localPosition用户触摸点相对于容器的坐标即触摸点在检测手势的组件内的坐标。
delta用户自上次更新以来移动的距离偏移量。可以用来计算拖动的速度或方向。
primaryDelta如果拖动是单向的水平或垂直这将返回沿主要轴的偏移量。
使用示例
import package:flutter/material.dart;class PanUpdateExamplePage extends StatelessWidget {const PanUpdateExamplePage({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(onPanUpdate Example)),body: const Center(child: PanUpdateExampleWidget(),),);}
}class PanUpdateExampleWidget extends StatefulWidget {const PanUpdateExampleWidget({super.key});override_PanUpdateExampleState createState() {return _PanUpdateExampleState();}
}class _PanUpdateExampleState extends StatePanUpdateExampleWidget {Offset _position Offset.zero;overrideWidget build(BuildContext context) {return GestureDetector(onPanUpdate: (DragUpdateDetails details) {setState(() {_position details.delta;});},child: Stack(children: [Positioned(left: _position.dx,top: _position.dy,child: Container(width: 100,height: 100,color: Colors.blue,child: const Center(child: Text(Drag me,style: TextStyle(color: Colors.white),),),))],),);}
}onPanStart onPanStart 是 GestureDetector 组件中的一个回调用于处理用户的拖动或平移手势的开始事件。当用户在屏幕上开始拖动时onPanStart 会被触发。它是实现拖动交互的第一步通常与 onPanUpdate 和 onPanEnd 一起使用来处理完整的拖动事件。
主要特性
触发时机当用户用手指触摸屏幕并开始拖动时立即触发。
事件细节回调函数接收一个 DragStartDetails 对象提供有关手势开始的详细信息。
DragStartDetails 的重要属性
globalPosition用户触摸点相对于整个屏幕的坐标。
localPosition用户触摸点相对于手势检测区域的坐标即触摸点在 GestureDetector 的子组件内的坐标。
使用案例
import package:flutter/material.dart;class PanStartExamplePage extends StatelessWidget {const PanStartExamplePage({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(onPanStart Example)),body: const Center(child: PanStartExampleWidget(),),);}
}class PanStartExampleWidget extends StatefulWidget {const PanStartExampleWidget({super.key});override_PanStartExampleState createState() {return _PanStartExampleState();}
}class _PanStartExampleState extends StatePanStartExampleWidget {Offset _startPosition Offset.zero;overrideWidget build(BuildContext context) {return GestureDetector(onPanStart: (details) {setState(() {_startPosition details.localPosition;});},child: Container(width: 200,height: 200,color: Colors.blue,child: Center(child: Text(Start Position: $_startPosition,style: const TextStyle(color: Colors.white)),),),);}
}CustomPaint
CustomPaint 是 Flutter 中的一个强大组件用于在屏幕上自定义绘制内容。通过 CustomPaint你可以在 Flutter 应用中创建复杂的图形和视觉效果超越标准的 UI 组件。
主要组件
CustomPaint这是一个 widget它包含一个 painter 和一个 child。painter 用于自定义绘制child 是可选的在绘制内容之上显示。
CustomPainter一个抽象类需要实现其中的 paint 和 shouldRepaint 方法。paint 方法定义了具体的绘制逻辑而 shouldRepaint 决定了何时需要重绘。
关键方法
paint(Canvas canvas, Size size)在此方法中实现具体的绘制逻辑。通过 Canvas 对象在给定的 Size 上绘制图形。
shouldRepaint(CustomPainter oldDelegate)返回一个布尔值指示当 CustomPaint 的配置变化时是否需要重绘。通常在绘制逻辑或者输入参数变化时返回 true。 使用案例
import package:flutter/material.dart;class CirclePainter extends CustomPainter {overridevoid paint(Canvas canvas, Size size) {final paint Paint()..color Colors.blue..style PaintingStyle.fill;final center Offset(size.width / 2, size.height / 2);final radius size.width / 2;canvas.drawCircle(center, radius, paint);}overridebool shouldRepaint(covariant CustomPainter oldDelegate) {return false; // 如果绘制内容不变返回 false 以提高性能}
}import package:flutter/material.dart;
import package:gsy_flutter_demo/widget/circle_painter.dart;class CustomPaintExamplePage extends StatelessWidget {const CustomPaintExamplePage({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(CustomPaint Example)),body: Center(child: CustomPaint(size: const Size(100, 100),painter: CirclePainter(),),),);}
}
注意事项
性能由于自定义绘制可能涉及大量计算因此要小心处理绘制逻辑确保 shouldRepaint 返回正确的值以避免不必要的重绘。绘制顺序CustomPaint 的 child 会在 painter 绘制之后显示这意味着绘制的内容将在 child 背后。交互CustomPaint 不支持手势检测。如果需要交互可以将其包裹在 GestureDetector 中。 Expanded
Expanded 是 Flutter 中一个非常常用的 widget通常用于在 Row, Column 或 Flex 组件中按比例扩展子组件的可用空间。它通过灵活地分配空间帮助创建响应式的布局。
主要特性
自动填充空间Expanded 使用 flex 属性占据父组件中未被占用的可用空间。
比例分配通过 flex 属性可以为多个 Expanded 组件指定占用空间的比例。
简化布局在需要将多个子组件平分或按比例分配空间时Expanded 是一个非常便利的工具。
使用示例
import package:flutter/material.dart;class ExpandExampleWidget extends StatelessWidget {const ExpandExampleWidget({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(Expanded Example),),body: Column(children: Widget[Container(color: Colors.red,height: 100,child: const Center(child: Text(Fixed Height),),),Expanded(flex: 2,child: Container(color: Colors.green,child: const Center(child: Text(Expanded\nFlex: 2)),),),Expanded(flex: 1,child: Container(color: Colors.blue,child: const Center(child: Text(Expanded\nFlex: 1)),),),],),);}
}注意事项
父组件限制Expanded 只能用于 Row, Column 或 Flex 类型的父组件中不能在其他布局如 Stack 或 ListView中使用。可用空间Expanded 只能填充父组件中未被占用的空间。因此如果父组件没有剩余空间比如 Row 中所有子组件都有固定宽度Expanded 将不起作用。嵌套使用可以嵌套使用多个 Expanded 组件以便在复杂布局中根据需要分配空间。交替使用与 Flexible 一起使用时Expanded 会占用所有的可用空间而 Flexible 则可以根据其子组件的大小来调整。 Expanded 是 Flutter 布局系统中的一个重要工具尤其在构建响应式用户界面时非常有用。通过合理使用 Expanded可以轻松实现子组件的动态布局和空间分配。它简化了构建灵活且美观。 EdgeInsets.only
EdgeInsets.only 是 Flutter 中用于创建具有特定边距的 EdgeInsets 对象的构造函数。EdgeInsets 是 Flutter 的布局系统中用于定义控件的内边距或外边距的一个类。通过 EdgeInsets.only你可以为某个控件指定具体的边距值只作用于指定的边。
主要特性
指定边距可以为四个边左、上、右、下中的任意一个或多个边指定具体的边距值。
灵活控制允许开发者精确控制每一边的间距而不需要统一设置所有边的边距。
基本用法
EdgeInsets.only 可以在任何支持 EdgeInsets 的属性中使用例如 Padding, Margin, Container 的 padding 和 margin 属性等。 使用案例
import package:flutter/material.dart;class EdgeInsetsOnlyExamplePage extends StatelessWidget {const EdgeInsetsOnlyExamplePage({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(EdgeInsets.only Example)),body: Center(child: Container(color: Colors.blueAccent,child: const Padding(padding: EdgeInsets.only(left: 20.0, top: 10.0),child: Text(Hello, Flutter!,style: TextStyle(color: Colors.white, fontSize: 24),),),),),);}
} 其他相关构造函数
EdgeInsets.all(double value)为四个边设置相同的边距。
EdgeInsets.symmetric({double vertical, double horizontal})同时为水平和垂直方向设置对称的边距。
EdgeInsets.fromLTRB(double left, double top, double right, double bottom)为四个边分别设置具体的边距。
EdgeInsets.zero用于设置没有边距的 EdgeInsets。 使用注意事项
布局影响边距的设置会影响布局尤其是在复杂的布局中要确保边距设置与设计需求一致。
嵌套使用可以将多个 EdgeInsets 结合使用以实现更复杂的布局效果。
响应式设计在需要适配不同屏幕或设备时可以结合 MediaQuery 动态调整 EdgeInsets 的值。
通过使用 EdgeInsets.only开发者可以在布局中实现更精细的控制确保每个控件的间距符合设计规范。它是 Flutter 布局系统中不可或缺的一部分提供了灵活而强大的布局能力。 EdgeInsets.zero
EdgeInsets.zero 是 Flutter 中 EdgeInsets 类的一个常量它表示没有边距即上下左右的边距都为 0。在布局中使用 EdgeInsets.zero 可以明确指定某个控件不需要额外的内边距或外边距。
主要用途
消除默认边距在某些情况下控件可能会有默认的边距或内边距通过使用 EdgeInsets.zero 可以去除这些默认的边距。
明确意图即使边距默认为 0使用 EdgeInsets.zero 可以让代码更加清晰表示边距的设计是经过有意定义的。
条件布局在需要根据条件动态设置边距时可以方便地使用 EdgeInsets.zero 来代表没有边距的选项。
使用案例
import package:flutter/material.dart;class EdgeInsetsZeroExample extends StatelessWidget {const EdgeInsetsZeroExample({super.key});overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text(EdgeInsets.zero Example)),body: Center(child: Container(color: Colors.blueAccent,padding: EdgeInsets.zero,child: const Text(No Padding,style: TextStyle(color: Colors.white, fontSize: 24),),),),);}
}其他相关用法
与条件语句结合在构建动态布局时可以通过条件语句选择使用 EdgeInsets.zero 或其他 EdgeInsets 值。
EdgeInsets padding condition ? EdgeInsets.all(10.0) : EdgeInsets.zero;
默认值清除某些 Flutter 组件可能有默认的边距设置通过使用 EdgeInsets.zero 可以显式地清除这些默认设置。
注意事项
布局影响使用 EdgeInsets.zero 会使得组件内容紧贴其父容器的边界确保这是预期的效果。
代码可读性即使某个属性的默认值为 0使用 EdgeInsets.zero 可以提高代码的可读性和可维护性明确表明设计选择。
通过使用 EdgeInsets.zero开发者可以在布局中实现无边距的设计确保控件准确地呈现设计意图。这在需要精确控制 UI 元素位置的场景中特别有用。 自定义提示弹框实现学习
import package:flutter/material.dart;import bubble_painter.dart;///提示弹框
class BubbleTipWidget extends StatefulWidget {///控件高度final double? height;///控件宽度final double? width;///控件圆角final double? radius;///控件文本final String text;///需要三角形指向的x坐标final double? x;///需要三角形指向的y坐标final double? y;///三角形的位置final ArrowLocation arrowLocation;final VoidCallback? voidCallback;const BubbleTipWidget({super.key, this.width,this.height,this.radius,this.text ,this.arrowLocation ArrowLocation.BOTTOM,this.voidCallback,this.x 0,this.y 0});overrideStateStatefulWidget createState() _BubbleTipWidgetState();
}class _BubbleTipWidgetState extends StateBubbleTipWidgetwith SingleTickerProviderStateMixin {AnimationController? progressController;final GlobalKey paintKey GlobalKey();overridevoid initState() {super.initState();}overrideWidget build(BuildContext context) {double arrowHeight 10;double arrowWidth 10;double? x widget.x;double? y widget.y;Size size MediaQuery.sizeOf(context);///计算出位置的中心点if (widget.arrowLocation ArrowLocation.BOTTOM ||widget.arrowLocation ArrowLocation.TOP) {x widget.x! - widget.width! / 2;} else {y widget.y! - widget.height! / 2;}///宽度是否超出bool widthOut (widget.width! x!) size.width || x 0;///高度是否超出bool heightOut (widget.height! y!) size.height || y 0;///不能小于0if (x 0) {x 0;} else if (widthOut) {x size.width - widget.width!;}if (y 0) {y 0;} else if (heightOut) {y size.height - widget.height!;}///箭头在这个状态下是否需要居中bool arrowCenter (widget.arrowLocation ArrowLocation.BOTTOM ||widget.arrowLocation ArrowLocation.TOP)? !widthOut: !heightOut;///调整箭头状态因为此时箭头会可能不是局中的double arrowPosition (widget.arrowLocation ArrowLocation.BOTTOM ||widget.arrowLocation ArrowLocation.TOP)? (widget.x! - x - arrowWidth / 2): (widget.y! - y - arrowHeight / 2);///箭头的位置是按照弹出框的左边为起点计算的if (widget.arrowLocation ArrowLocation.BOTTOM ||widget.arrowLocation ArrowLocation.TOP) {if (arrowPosition widget.radius! 2) {arrowPosition widget.radius! 4;} else if (arrowPosition widget.width! - widget.radius! - 2) {arrowPosition widget.width! - widget.radius! - 4;}} else {if (arrowPosition widget.radius! 2) {arrowPosition widget.radius! 4;} else if (x widget.height! - widget.radius! - 2) {arrowPosition widget.height! - widget.radius! - 4;}}EdgeInsets margin EdgeInsets.zero;if (widget.arrowLocation ArrowLocation.TOP) {margin EdgeInsets.only(top: arrowHeight, right: 5, left: 5);}var bubbleBuild BubbleBuilder()..mAngle widget.radius..mArrowHeight arrowHeight..mArrowWidth arrowWidth..mArrowPosition arrowPosition..mArrowLocation widget.arrowLocation..arrowCenter arrowCenter;var alignment Alignment.centerLeft;if(widget.arrowLocation ArrowLocation.TOP || widget.arrowLocation ArrowLocation.BOTTOM) {alignment Alignment.center;}return Scaffold(backgroundColor: Colors.transparent,body: GestureDetector(///透明可以点击behavior: HitTestBehavior.translucent,onPanStart: _onPanStart,onPanUpdate: _onPanUpdate,onPanEnd: _onPanEnd,child: Container(alignment: Alignment.centerLeft,width: widget.width,height: widget.height,margin: EdgeInsets.only(left: x, top: y),child: Stack(children: Widget[///绘制气泡背景CustomPaint(key: paintKey,size: Size(widget.width!, widget.height!),painter: bubbleBuild.build()),Align(alignment: alignment,///显示文本等child: Container(margin: margin,width: widget.width,height: widget.height! - arrowHeight,alignment: Alignment.centerLeft,child: Row(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: Widget[Container(margin: const EdgeInsets.only(left: 20),height: widget.height,child: Icon(Icons.notifications,size: widget.height! - 30,color: Theme.of(context).primaryColorDark,),),Expanded(child: Container(margin: const EdgeInsets.only(left: 5, right: 5),child: Text(widget.text,style: const TextStyle(fontSize: 14, color: Colors.black),),),)],),),)],),),),);}void _onPanStart(DragStartDetails details) {}void _onPanUpdate(DragUpdateDetails details) {}void _onPanEnd(DragEndDetails details) {widget.voidCallback?.call();}
} 文章转载自: http://www.morning.zqzhd.cn.gov.cn.zqzhd.cn http://www.morning.zwppm.cn.gov.cn.zwppm.cn http://www.morning.qngcq.cn.gov.cn.qngcq.cn http://www.morning.jkrrg.cn.gov.cn.jkrrg.cn http://www.morning.qqrlz.cn.gov.cn.qqrlz.cn http://www.morning.mhxlb.cn.gov.cn.mhxlb.cn http://www.morning.lwmzp.cn.gov.cn.lwmzp.cn http://www.morning.wchsx.cn.gov.cn.wchsx.cn http://www.morning.qmtzq.cn.gov.cn.qmtzq.cn http://www.morning.fnfxp.cn.gov.cn.fnfxp.cn http://www.morning.hsflq.cn.gov.cn.hsflq.cn http://www.morning.mbrbk.cn.gov.cn.mbrbk.cn http://www.morning.nlbhj.cn.gov.cn.nlbhj.cn http://www.morning.rswfj.cn.gov.cn.rswfj.cn http://www.morning.tsxg.cn.gov.cn.tsxg.cn http://www.morning.wtcyz.cn.gov.cn.wtcyz.cn http://www.morning.qjlkp.cn.gov.cn.qjlkp.cn http://www.morning.yrdt.cn.gov.cn.yrdt.cn http://www.morning.mlbdr.cn.gov.cn.mlbdr.cn http://www.morning.jhyfb.cn.gov.cn.jhyfb.cn http://www.morning.gsksm.cn.gov.cn.gsksm.cn http://www.morning.qcmhs.cn.gov.cn.qcmhs.cn http://www.morning.chzbq.cn.gov.cn.chzbq.cn http://www.morning.lqchz.cn.gov.cn.lqchz.cn http://www.morning.ggqcg.cn.gov.cn.ggqcg.cn http://www.morning.qnhpq.cn.gov.cn.qnhpq.cn http://www.morning.mjytr.cn.gov.cn.mjytr.cn http://www.morning.rnpnn.cn.gov.cn.rnpnn.cn http://www.morning.kllzy.com.gov.cn.kllzy.com http://www.morning.qhjkz.cn.gov.cn.qhjkz.cn http://www.morning.hhxkl.cn.gov.cn.hhxkl.cn http://www.morning.jzyfy.cn.gov.cn.jzyfy.cn http://www.morning.nrzbq.cn.gov.cn.nrzbq.cn http://www.morning.pjfmq.cn.gov.cn.pjfmq.cn http://www.morning.brbmf.cn.gov.cn.brbmf.cn http://www.morning.bpmdz.cn.gov.cn.bpmdz.cn http://www.morning.rpljf.cn.gov.cn.rpljf.cn http://www.morning.mkpqr.cn.gov.cn.mkpqr.cn http://www.morning.xkwrb.cn.gov.cn.xkwrb.cn http://www.morning.qrzqd.cn.gov.cn.qrzqd.cn http://www.morning.nydtt.cn.gov.cn.nydtt.cn http://www.morning.jgykx.cn.gov.cn.jgykx.cn http://www.morning.rhkq.cn.gov.cn.rhkq.cn http://www.morning.lznqb.cn.gov.cn.lznqb.cn http://www.morning.nwtmy.cn.gov.cn.nwtmy.cn http://www.morning.wsrcy.cn.gov.cn.wsrcy.cn http://www.morning.zfcfx.cn.gov.cn.zfcfx.cn http://www.morning.mflqd.cn.gov.cn.mflqd.cn http://www.morning.jfwbr.cn.gov.cn.jfwbr.cn http://www.morning.hgfxg.cn.gov.cn.hgfxg.cn http://www.morning.rjmd.cn.gov.cn.rjmd.cn http://www.morning.dpbdq.cn.gov.cn.dpbdq.cn http://www.morning.wdlyt.cn.gov.cn.wdlyt.cn http://www.morning.tnkwj.cn.gov.cn.tnkwj.cn http://www.morning.ztcxx.com.gov.cn.ztcxx.com http://www.morning.mjzgg.cn.gov.cn.mjzgg.cn http://www.morning.qcslh.cn.gov.cn.qcslh.cn http://www.morning.leeong.com.gov.cn.leeong.com http://www.morning.bzsqr.cn.gov.cn.bzsqr.cn http://www.morning.knswz.cn.gov.cn.knswz.cn http://www.morning.hphfy.cn.gov.cn.hphfy.cn http://www.morning.gassnw.com.gov.cn.gassnw.com http://www.morning.dnmzl.cn.gov.cn.dnmzl.cn http://www.morning.jrbyz.cn.gov.cn.jrbyz.cn http://www.morning.rkxqh.cn.gov.cn.rkxqh.cn http://www.morning.rlqwz.cn.gov.cn.rlqwz.cn http://www.morning.hsklc.cn.gov.cn.hsklc.cn http://www.morning.nrbqf.cn.gov.cn.nrbqf.cn http://www.morning.pqktp.cn.gov.cn.pqktp.cn http://www.morning.kyflr.cn.gov.cn.kyflr.cn http://www.morning.ylqrc.cn.gov.cn.ylqrc.cn http://www.morning.bxqry.cn.gov.cn.bxqry.cn http://www.morning.sqqpb.cn.gov.cn.sqqpb.cn http://www.morning.jbpdk.cn.gov.cn.jbpdk.cn http://www.morning.duqianw.com.gov.cn.duqianw.com http://www.morning.tsdqr.cn.gov.cn.tsdqr.cn http://www.morning.qjzgj.cn.gov.cn.qjzgj.cn http://www.morning.ubpsa.cn.gov.cn.ubpsa.cn http://www.morning.jfgmx.cn.gov.cn.jfgmx.cn http://www.morning.nlkhr.cn.gov.cn.nlkhr.cn