# flutter_demo **Repository Path**: lywhao/flutter_demo ## Basic Information - **Project Name**: flutter_demo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-11-02 - **Last Updated**: 2024-05-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # flutter_demo A new Flutter project. https://book.flutterchina.club/chapter6/scroll_controller.html#_6-4-1-scrollcontroller ## Getting Started pubspec.yaml 第三方库 StatelessWidget StatefulWidget 每次更新都會調用build ## 容器 ### ###Scaffold appBar 顶部 body 界面显示 drawer抽屉菜单 ### ###Container Container是一个组合类容器,它本身不对应具体的RenderObject,它是DecoratedBox、ConstrainedBox、Transform、Padding、Align等组件组合的一个多功能容器, 所以我们只需通过一个Container组件可以实现同时需要装饰、变换、限制的场景。 可以让我们设置一个控件的尺寸、背景、margin Container({ this.alignment, this.padding, //容器内补白,属于decoration的装饰范围 Color color, // 背景色 Decoration decoration, // 背景装饰 Decoration foregroundDecoration, //前景装饰 double width,//容器的宽度 double height, //容器的高度 BoxConstraints constraints, //容器大小的限制条件 this.margin,//容器外补白,不属于decoration的装饰范围 this.transform, //变换 this.child, ... }) ###Padding 设置一个控件的pad ###Center 容器 把一个控件放在中间 ###Column 水平列表容器 // main axis 跟我们前面提到的 cross axis 相对应,对 Column 来说,指的就是竖直方向。 // 在放置完子控件后,屏幕上可能还会有一些剩余的空间(free space),min 表示尽量少占用 // free space;类似于 Android 的 wrap_content。 // 对应的,还有 MainAxisSize.max mainAxisSize: MainAxisSize.min, // 沿着 main axis 居中放置 mainAxisAlignment: MainAxisAlignment.center, ###Row 垂直列表容器 ###Expanded 只在Row、Column等组件内,不在其他组件内使用。 占满剩余空间 flex 多个Expanded,设置权重 ###Flexible 只在Row、Column等组件内,不在其他组件内使用。 ###Stack 子控件都按 Stack 的左上角对齐,一个控件叠在另一个控件的上面 ###装饰容器DecoratedBox DecoratedBox可以在其子组件绘制前(或后)绘制一些装饰(Decoration),如背景、边框、渐变等 BoxDecoration({ Color color, //颜色 DecorationImage image,//图片 BoxBorder border, //边框 BorderRadiusGeometry borderRadius, //圆角 List boxShadow, //阴影,可以指定多个 Gradient gradient, //渐变 BlendMode backgroundBlendMode, //背景混合模式 BoxShape shape = BoxShape.rectangle, //形状 }) ###FittedBox 1. FittedBox 在布局子组件时会忽略其父组件传递的约束,可以允许子组件无限大, 即FittedBox 传递给子组件的约束为(0<=width<=double.infinity, 0<= height <=double.infinity)。 2. FittedBox 对子组件布局结束后就可以获得子组件真实的大小。 3. FittedBox 知道子组件的真实大小也知道他父组件的约束, 那么FittedBox 就可以通过指定的适配方式(BoxFit 枚举中指定), 让起子组件在 FittedBox 父组件的约束范围内按照指定的方式显示。 const FittedBox({ Key? key, this.fit = BoxFit.contain, // 适配方式 this.alignment = Alignment.center, //对齐方式 this.clipBehavior = Clip.none, //是否剪裁 Widget? child, }) ##剪裁(Clip) |-|-| |剪裁Widget | 默认行为 |ClipOval |子组件为正方形时剪裁成内贴圆形;为矩形时,剪裁成内贴椭圆 |ClipRRect | 将子组件剪裁为圆角矩形 |ClipRect |默认剪裁掉子组件布局空间之外的绘制内容(溢出部分剪裁) |ClipPath |按照自定义的路径剪裁 ##滚动组件 ###SingleChildScrollView SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件,定义如下 SingleChildScrollView({ this.scrollDirection = Axis.vertical, //滚动方向,默认是垂直方向 this.reverse = false, this.padding, bool primary, this.physics, this.controller, this.child, }) ###ScrollController ScrollController来控制可滚动组件的滚动位置 ScrollController({ double initialScrollOffset = 0.0, //初始滚动位置 this.keepScrollOffset = true,//是否保存滚动位置 ... }) ###GridView GridView({ Key? key, Axis scrollDirection = Axis.vertical, bool reverse = false, ScrollController? controller, bool? primary, ScrollPhysics? physics, bool shrinkWrap = false, EdgeInsetsGeometry? padding, required this.gridDelegate, //下面解释 bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, double? cacheExtent, List children = const [], ... }) gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子组件如何排列(layout) Flutter中提供了两个SliverGridDelegate的子类 SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent #### SliverGridDelegateWithFixedCrossAxisCount 该子类实现了一个横轴为固定数量子元素的layout算法 SliverGridDelegateWithFixedCrossAxisCount({ @required double crossAxisCount, double mainAxisSpacing = 0.0, double crossAxisSpacing = 0.0, double childAspectRatio = 1.0, }) crossAxisCount:横轴子元素的数量。此属性值确定后子元素在横轴的长度就确定了,即ViewPort横轴长度除以crossAxisCount的商。 mainAxisSpacing:主轴方向的间距。 crossAxisSpacing:横轴方向子元素的间距。 childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后,子元素横轴长度就确定了,然后通过此参数值就可以确定子元素在主轴的长度。 #### SliverGridDelegateWithMaxCrossAxisExtent 该子类实现了一个横轴子元素为固定最大长度的layout算法 ``` SliverGridDelegateWithMaxCrossAxisExtent({ double maxCrossAxisExtent, double mainAxisSpacing = 0.0, double crossAxisSpacing = 0.0, double childAspectRatio = 1.0, }) ``` maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的, 举个例子,如果ViewPort的横轴长度是450,那么当maxCrossAxisExtent的值在区间[450/4,450/3)内的话, 子元素最终实际长度都为112.5,而childAspectRatio所指的子元素横轴和主轴的长度比为最终的长度比。 其它参数和SliverGridDelegateWithFixedCrossAxisCount相同。 ### PageView 如果要实现页面切换和 Tab 布局,我们可以使用 PageView 组件。需要注意,PageView 是一个非常重要的组件,因为在移动端开发中很常用,比如大多数 App 都包含 Tab 换页效果、图片轮动以及抖音上下滑页切换视频功能等等,这些都可以通过 PageView 轻松实现。 ```dart PageView({ Key? key, this.scrollDirection = Axis.horizontal, // 滑动方向 this.reverse = false, PageController? controller, this.physics, List children = const [], this.onPageChanged, //每次滑动是否强制切换整个页面,如果为false,则会根据实际的滑动距离显示页面 this.pageSnapping = true, //主要是配合辅助功能用的,后面解释 this.allowImplicitScrolling = false, //后面解释 this.padEnds = true, }) ``` ## TabBarView TabBarView 封装了 PageView,它的构造方法很简单 ```dart TabBarView({ Key? key, required this.children, // tab 页 this.controller, // TabController this.physics, this.dragStartBehavior = DragStartBehavior.start, }) ``` ## ##控件 ###Text 文本控件 |--|--| |属性|说明| |overflow| 文字超出屏幕后处理【clip 裁剪,fade 渐隐 ellipsis 省略号】| |textScaleFactor |字体显示倍率| |style|样式| ###Image 图片控件 图片的来源可以是网络、文件、资源和内存 Image.asset(name); Image.file(file); Image.memory(bytes); Image.network(src); color 背景色 colorBlendMode 背景色和图片混合模式 fit 缩放模式 //设置圆形图片 leading: ClipOval( //圆形图片 child: Image.network("xxx", fit:BoxFit.cover,height: 60,width: 60 ,), ), ###TextField 输入控件 需搭配TextEditingController 获取输入文本 TextField(controller: control, decoration: InputDecoration(hintText: "name", labelText: "input"), style: TextStyle(),) ###TextButton 按钮 TextButton(onPressed: () => print("TextButton click"), child: Text("TextButton")) ###ElevatedButton 按钮 ElevatedButton(onPressed: () => print("ElevatedButton click"), child: Text("ElevatedButton")) ##事件 ###Listener ``` Listener({ Key? key, this.onPointerDown, this.onPointerMove, this.onPointerUp, this.onPointerHover, this.onPointerCancel, this.onPointerSignal, this.behavior = HitTestBehavior.deferToChild, Widget? child, }) ``` ### 忽略指针事件 假如我们不想让某个子树响应`PointerEvent`的话,我们可以使用`IgnorePointer`和`AbsorbPointer`,这两个组件都能阻止子树接收指针事件,不同之处在于`AbsorbPointer`本身会参与命中测试,而`IgnorePointer`本身不会参与,这就意味着`AbsorbPointer`本身是可以接收指针事件的(但其子树不行),而`IgnorePointer`不可以 ## GestureDetector `GestureDetector`是一个用于手势识别的功能性组件,我们通过它可以来识别各种手势。`GestureDetector` 内部封装了 Listener,用以识别语义化的手势,接下来我们详细介绍一下各种手势的识别。