组件1:MaterialApp、Container、Text、Image、Icon
组件2:ListView、GridView
组件3:Padding、Row 、Column、Stack、Align、Positioned
组件4:AspectRatio、Row 、Button
组件5:Wrap、StatelessWidget 、StatefulWidget、Dialog、PageView、TextField
3.16 Wrap
Wrap可以为子控件进行水平或者垂直方向布局,且当空间用完时,Wrap会自动换行,也是常说的流式布局
名称 | 功能 |
---|---|
direction | 排列方向,默认水平方向排列 |
alignment | 子控件在主轴上的对齐方式 |
spacing | 主轴上子控件中间的间距 |
runAlignment | 子控件在交叉轴上的对齐方式 |
runSpacing | 交叉轴上子控件之间的间距 |
crossAxisAlignment | 交叉轴上子控件的对齐方式 |
textDirection | textDirection水平方向上子控件的起始位置 |
verticalDirection | 垂直方向上子控件的其实位置 |
children |
3.17 StatelessWidget 和 StatefulWidget
参考:https://blog.csdn.net/qq_30963589/article/details/112561639
在Flutter开发中,我们一般都不用直接继承Widget类来实现一个新组件,相反,我们通常会通过继承StatelessWidget或StatefulWidget来间接继承Widget类来实现。
StatelessWidget和StatefulWidget都是直接继承自Widget类,而这两个类也正是Flutter中非常重要的两个抽象类,它们引入了两种Widget模型.
3.17.1 StatelessWidget
StatelessWidget
继承于Widget
类,他重写了creatElement()
方法。
@override
StatelessElement createElement() => new StatelessElement(this);
StatelessWidget
用于不需要维护状态
的场景,它通常在build
方法中通过嵌套其它Widget
来构建UI
,在构建过程中会递归的构建其嵌套的Widget
。
我们一般构建静态的UI的时候会使用StatelessWidget
3.17.2 StatefulWidget
StatefulWidget
也是继承于Widget
类,内部也重写了creatElement()
,不过与StatelessWidget
不同的是返回的Element
对象并不相同;
另外StatefulWidget
类中添加了一个新的接口createState()
。
abstract class StatefulWidget extends Widget {
// 为子类初始化[key]。
const StatefulWidget({ Key key }) : super(key: key);
//创建一个[StatefulElement]来管理此小部件在树中的位置。
@override
StatefulElement createElement() => StatefulElement(this);
// 在树中的给定位置为此小部件创建可变状态
@protected
@factory
State createState();
}
对StatefulWidget
来说,State
是核心,State
表示与其对应的StatefulWidget
要维护的状态
.一个StatefulWidget
对应一个State
.
State保存的信息:
在widget 构建时可以被同步读取。
在widget生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其build方法重新构建widget树,从而达到更新UI的目的。
每次 setState() 的时候都会重新调用 build方法,所以有些组件前面加 const 关键字,是为了再次build的时候,不会重新创建该组件。虽然不加const也不会有错误,但是对性能会有影响。
动态添加列表代码
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
home: HomePage(),
));
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final List _dataList = [];
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Demo"),
),
body: ListView(
children: _dataList.map((e) {
return ListTile(
title: e,
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_count++;
_dataList.add(Text("列表项 $_count"));
});
},
child: const Icon(Icons.add),
),
);
}
}
3.18 Dialog
3.18.1 AlertDialog
AlertDialog 是一个用于向用户传递信息的弹出层
import 'package:flutter/material.dart';
class Category extends StatefulWidget {
const Category({super.key});
@override
State<Category> createState() => _CategoryState();
}
class _CategoryState extends State<Category> {
void _alertDialog() async {
var result = await showDialog(
context: context,
builder: ((context) {
return AlertDialog(
title: const Text("提示信息!"),
content: const Text("这是提示的信息内容"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop("ok"); // 点击按钮让AlertDialog消失
},
child: const Text("确定")),
TextButton(
onPressed: () {
Navigator.of(context).pop("cancel");
},
child: const Text("取消"))
],
);
}));
print(result);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton( onPressed: _alertDialog, child: const Text("AlertDialog"))
],
);
}
}
3.18.2 SimpleDialog
为用户几个提供选项,可选标题,标题在选项上不边的信息弹出窗.
import 'package:flutter/material.dart';
class Category extends StatefulWidget {
const Category({super.key});
@override
State<Category> createState() => _CategoryState();
}
class _CategoryState extends State<Category> {
void _simpleDialog() async {
var result = await showDialog(
// 点击背景灰色dialog消失
barrierDismissible: true,
context: context,
builder: ((context) {
return SimpleDialog(
title: const Text("请选择语言"),
children: [
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, "chinese");
},
child: const Text("汉语"),
),
const Divider(),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, "english");
},
child: const Text("英语"),
),
const Divider(),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, "Janese");
},
child: const Text("日语"),
),
],
);
}));
print(result);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton( onPressed: _simpleDialog, child: const Text("SimpleDialog"))
],
);
}
}
3.18.3 showModalBottomSheet
底部面板,相当于弹出了一个新页面默认点击消失,可以给子组件外面包一层GestureDetector并设置onTap返回false,拦截点击事件使点击底部面板区域,面板不消失。底部面板的高度是有限制的,不能设置全屏高度
import 'package:flutter/material.dart';
class Category extends StatefulWidget {
const Category({super.key});
@override
State<Category> createState() => _CategoryState();
}
class _CategoryState extends State<Category> {
void _modelBottomSheet() async {
var result = await showModalBottomSheet(
context: context,
builder: ((context) {
return SizedBox(
height: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ListTile(
title: const Text("分享"),
onTap: () {
Navigator.of(context).pop("share");
},
),
Divider(),
ListTile(
title: const Text("收藏"),
onTap: () {
Navigator.of(context).pop("shoucang");
},
),
Divider(),
ListTile(
title: const Text("取消"),
onTap: () {
Navigator.of(context).pop("cancel");
},
)
],
),
);
}));
print(result);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton( onPressed: _modelBottomSheet, child: const Text("BottomSheet")),
],
);
}
}
3.19 PageView
名称 | 功能 |
---|---|
scrollDirection | Axis.horizontal水平方向,Axis.vertical垂直方向 |
children | |
allowImplicitScrolling | 缓存前2页 |
PageView控件可以实现一个“图片轮播”的效果,PageView不仅可以水平滑动也可以垂直滑动,简单用法如下:
PageView(
children: <Widget>[
MyPage1(),
MyPage2(),
MyPage3(),
],
)
使用 PageView.builder
import 'package:flutter/material.dart';
class BannerBuilder extends StatefulWidget {
const BannerBuilder({super.key});
@override
State<BannerBuilder> createState() => _BannerBuilderState();
}
class _BannerBuilderState extends State<BannerBuilder> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("pageViewBuileer"),
),
body: PageView.builder(
//当页面选中后回调此方法
//参数[index]是当前滑动到的页面角标索引 从0开始
onPageChanged: (int index) {
print("当前的页面是 $index");
},
//值为flase时 显示第一个页面 然后从左向右开始滑动
//值为true时 显示最后一个页面 然后从右向左开始滑动
reverse: false,
//滑动到页面底部无回弹效果
physics: BouncingScrollPhysics(),
itemCount: 10,
//纵向滑动切换
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Center(
child: Text(
"第${index + 1}屏",
style: Theme.of(context).textTheme.bodyText1,
));
}),
);
}
}
使用pageController 和 timer 控制自动轮播
import 'package:flutter/material.dart';
import 'dart:async';
class BannerBuilder extends StatefulWidget {
const BannerBuilder({super.key});
@override
State<BannerBuilder> createState() => _BannerBuilderState();
}
class _BannerBuilderState extends State<BannerBuilder> {
late PageController _pageController;
late Timer timer;
@override
void initState() {
// TODO: implement initState
super.initState();
// 初始化并设置
_pageController = PageController(initialPage: 0);
timer = Timer.periodic(const Duration(seconds: 5), (timer) {
// 参数1:跳到索引,参数2:动画时间,参数3:动画模式
_pageController.animateToPage(2,
duration: const Duration(milliseconds: 200), curve: Curves.linear);
});
}
@override
void dispose() {
// 销毁组件
super.dispose();
timer.cancel();
_pageController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("pageViewBuileer"),
),
body: PageView.builder(
// 设置controller
controller: _pageController,
// ...
);
}
}
3.20 TextField
const TextField({
Key key,
this.controller,//控制器
this.focusNode,//焦点
this.obscureText = false,//是否隐藏文本,即显示密码类型
this.maxLines = 1,//最多行数,高度与行数同步
this.autofocus = false,//自动聚焦
this.decoration = const InputDecoration(),//装饰
TextInputType keyboardType,//键盘类型,即输入类型
this.onChanged,//输入改变回调
//以下属性不常用,用到再来查看
this.textInputAction,//键盘按钮
this.textCapitalization = TextCapitalization.none,//大小写
this.style,//样式
this.strutStyle,
this.textAlign = TextAlign.start,//对齐方式
this.textDirection,
this.autocorrect = true,//自动更正
this.minLines,//最小行数
this.expands = false,
this.maxLength,//最多输入数,有值后右下角就会有一个计数器
this.maxLengthEnforced = true,
this.onEditingComplete,//输入完成时,配合TextInputAction.done使用
this.onSubmitted,//提交时,配合TextInputAction
this.inputFormatters,//输入校验
this.enabled,//是否可用
this.cursorWidth = 2.0,//光标宽度
this.cursorRadius,//光标圆角
this.cursorColor,//光标颜色
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection,
this.onTap,//点击事件
this.buildCounter,
this.scrollPhysics,
})
其中decoration
接收一个InputDecoration
类型的值,主要用于控制TextField的外观以及提示信息等 这里介绍下这个重要的Widget,
InputDecoration({
this.icon, //位于装饰器外部和输入框前面的图片
this.labelText, //用于描述输入框,例如这个输入框是用来输入用户名还是密码的,当输入框获取焦点时默认会浮动到上方,
this.labelStyle, // 控制labelText的样式,接收一个TextStyle类型的值
this.helperText, //辅助文本,位于输入框下方,如果errorText不为空的话,则helperText不会显示
this.helperStyle, //helperText的样式
this.hintText, //提示文本,位于输入框内部
this.hintStyle, //hintText的样式
this.hintMaxLines, //提示信息最大行数
this.errorText, //错误信息提示
this.errorStyle, //errorText的样式
this.errorMaxLines, //errorText最大行数
this.hasFloatingPlaceholder = true, //labelText是否浮动,默认为true,修改为false则labelText在输入框获取焦点时不会浮动且不显示
this.isDense, //改变输入框是否为密集型,默认为false,修改为true时,图标及间距会变小
this.contentPadding, //内间距
this.prefixIcon, //位于输入框内部起始位置的图标。
this.prefix, //预先填充的Widget,跟prefixText同时只能出现一个
this.prefixText, //预填充的文本,例如手机号前面预先加上区号等
this.prefixStyle, //prefixText的样式
this.suffixIcon, //位于输入框后面的图片,例如一般输入框后面会有个眼睛,控制输入内容是否明文
this.suffix, //位于输入框尾部的控件,同样的不能和suffixText同时使用
this.suffixText,//位于尾部的填充文字
this.suffixStyle, //suffixText的样式
this.counter,//位于输入框右下方的小控件,不能和counterText同时使用
this.counterText,//位于右下方显示的文本,常用于显示输入的字符数量
this.counterStyle, //counterText的样式
this.filled, //如果为true,则输入使用fillColor指定的颜色填充
this.fillColor, //相当于输入框的背景颜色
this.errorBorder, //errorText不为空,输入框没有焦点时要显示的边框
this.focusedBorder, //输入框有焦点时的边框,如果errorText不为空的话,该属性无效
this.focusedErrorBorder, //errorText不为空时,输入框有焦点时的边框
this.disabledBorder, //输入框禁用时显示的边框,如果errorText不为空的话,该属性无效
this.enabledBorder, //输入框可用时显示的边框,如果errorText不为空的话,该属性无效
this.border, //正常情况下的border
this.enabled = true, //输入框是否可用
this.semanticCounterText,
this.alignLabelWithHint,
})
修改下划线颜色,要同时修改2个样式
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xffeeeeee)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
无边框
TextField(
decoration: InputDecoration(border: InputBorder.none),
)
网友评论