flutter学习笔记
项目目录结构
lib/包含Dart代码,是应用程序的核心目录。通常会包含一个名为main.dart的文件,该文件是应用程序的入口点。主要在这个目录中实现App的主要功能android/包含Android原生代码和配置文件,例如gradle文件、AndroidManifest.xml等。在这个目录中可以进行Android原生相关的配置和自定义,例如添加自定义的Gradle插件或者添加第三方库等ios/包含iOS原生代码和配置文件,例如Xcode项目文件、Info.plist等。在这个目录中可以进行iOS原生相关的配置和自定义,例如添加自定义的CocoaPods依赖或者添加第三方库等test/包含应用程序的测试代码,通常使用Flutter自带的测试框架进行单元测试和集成测试pubspec.yaml应用程序的依赖和配置文件,其中包含了应用程序所依赖的第三方库的名称、版本以及其他配置信息webweb目录是Flutter项目的Web平台代码目录,用于在Web平台上运行Flutter应用程序windowswindows目录是Flutter项目的Windows平台代码目录,用于在Windows平台上运行Flutter应用程序
hello world
- lib/main.dart
import 'package:flutter/material.dart';
import 'components/myApp.dart';
void main() {
runApp(MyApp());
}
- lib/components/myApp.dart
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false, // 关闭右上角debug图标
home: HomePage(),
);
}
}
// body
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"这里是顶部",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blue,
),
body: ListView(
children: const [
Text(
"hello world",
style: TextStyle(
fontSize: 30,
color: Colors.deepOrange
),
),
MessageItem('https://img0.baidu.com/it/u=4227008132,2843866888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1084', '11111', '这是第一条数据'),
MessageItem('https://wx2.sinaimg.cn/mw690/005Dg9pggy1hq9jkfix5bj32554n17wh.jpg', '22222', '这是第二条数据'),
MessageItem('https://img0.baidu.com/it/u=2191392668,814349101&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1399', '33333', '这是第三条数据'),
CountPage(),
],
)
);
}
}
// 列表
class MessageItem extends StatelessWidget {
final imgUrl;
final name;
final msg;
const MessageItem(this.imgUrl, this.name, this.msg, {super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Row(
children: [
Image.network(imgUrl, width: 60, height: 60, fit: BoxFit.cover,),
const SizedBox(width: 10,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(name, style: TextStyle(fontSize: 18, color: Colors.black),),
const SizedBox(height: 3,),
Text(msg, style: TextStyle(fontSize: 14, color: Color.fromARGB(255,100,100,100)),)
],
),
],
)
);
}
}
// 计数器
class CountPage extends StatefulWidget {
const CountPage({super.key});
@override
State<StatefulWidget> createState() {
return CountState();
}
}
class CountState extends State<CountPage> {
int _count = 0;
// 减
void _onSub() {
setState(() {
_count <= 0 ? 0 : _count--;
});
}
// 加
void _onAdd() {
setState(() {
_count >= 10 ? 10 : _count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("计数器", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),),
Row(
children: [
const SizedBox(width: 10,),
IconButton(onPressed: _onSub, icon: const Icon(Icons.remove_circle)),
Text('$_count', style: TextStyle(fontSize: 30),),
IconButton(onPressed: _onAdd, icon: const Icon(Icons.add_box)),
],
)
],
);
}
}
国际化配置-中文
dependencies:
flutter:
sdk: flutter
flutter_localizations: # 添加这个内容(flutter SDK自带)
sdk: flutter
运行 flutter pub get
main.dart
import 'package:flutter/material.dart';
import 'package:my_tool/router/router.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; // 引入包
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final router = AppRouter();
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: router.router,
// 默认中文
locale: const Locale('zh', 'CN'),
// 声明
supportedLocales: const [Locale('zh', 'CN')],
// 注册本地化代理
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate, // Material组件本地化
GlobalWidgetsLocalizations.delegate, // 基础Widget本地化
GlobalCupertinoLocalizations.delegate, // iOS风格组件本地化
],
);
}
}
容器组件Container
width宽height高alignment内部对齐方式padding内边距margin外边距-
EdgeInsets.all()统一设置
-
EdgeInsets.fromLTRB()(left, top, right, bottom)
decoration组件的样式-
color背景
-
border边框
-
borderRadius圆角
-
boxShadow阴影
-
gradient渐变
transform动画child子元素
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
// ----------------------- Container -----------------------
child: Container(
width: 200, // 宽
height: 200, // 高
alignment: Alignment.topLeft, // 内部对齐方式
padding: const EdgeInsets.all(10), // 内边距
margin: const EdgeInsets.fromLTRB(10, 10, 10, 10), // 外边距(left, top, right, bottom)
// 组件的样式
decoration: BoxDecoration(
color: Colors.blue, // 背景
borderRadius: BorderRadius.circular(20), // 圆角
border: Border.all(color: Colors.black, width: 2), // 边框
// 阴影
boxShadow: const [
BoxShadow(
color: Colors.lightBlue, // 阴影颜色
blurRadius: 10, // 扩散
offset: Offset(10, 10), // 偏移(x, y)
)
],
// 渐变
gradient: const LinearGradient(colors: [
Colors.blue, Colors.white
])
),
// 子元素
child: Text(
'hello world',
style: TextStyle(fontSize: 20, color: Colors.white),
)
),
// ---------------------------------------------------------
),
);
}
}
文本组件Text
maxLines可显示的最大行数,超出默认隐藏textAlign文本对齐方式overflow文本超出容器后显示的样式(省略号)style文本样式-
color颜色
-
fontSize大小
-
fontWeight字体加粗
-
letterSpacing字体间隔
-
wordSpacing单词间隔
-
decoration修饰线
-
decorationColor修饰线颜色
-
decorationStyle修饰线样式
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
// ----------------------- Text -----------------------
child: Text(
'hello world, hello world, hello world, hello world, hello world, hello world,',
maxLines: 2, // 可显示的最大行数
textAlign: TextAlign.center, // 文本对齐方式
overflow: TextOverflow.ellipsis, // 文本超出容器后显示的样式(省略号)
// 文本样式
style: TextStyle(
color: Colors.blue, // 颜色
fontSize: 30, // 大小
fontWeight: FontWeight.bold, // 字体加粗
letterSpacing: 2, // 字体间隔
wordSpacing: 10, // 单词间隔
decoration: TextDecoration.underline, // 修饰线
decorationColor: Colors.red, // 修饰线颜色
decorationStyle: TextDecorationStyle.double, // 修饰线样式
),
)
// ---------------------------------------------------------
),
);
}
}
容器组件SizedBox
SizedBox和Container在布局方面的作用是很相似的- 只设置尺寸,用
SizedBox- 需要样式(颜色等),用
Container
width宽height高
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
// ----------------------- SizedBox -----------------------
child: const SizedBox(
width: 200,
height: 200,
child: Text('hello world, hello world, hello world, hello world, hello world, hello world,hello world, hello world, hello world, hello world, hello world, hello world,'),
)
// ---------------------------------------------------------
),
);
}
}
布局组件Center
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// ----------------------- Center -----------------------
body: Center(
child: Text('hello world'),
),
// ---------------------------------------------------------
);
}
}
布局组件Padding
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: Colors.blue,
),
// ----------------------- Padding -----------------------
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('hello world'),
)
// ---------------------------------------------------------
),
),
);
}
}
图片组件Image
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"这里是顶部",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blue,
),
body: Column(
children: [
// ----------------------- Image -----------------------
// 默认
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 2)
),
child: Image.network(
'https://img0.baidu.com/it/u=4227008132,2843866888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1084',
),
),
// ---------------------------------------------------------
],
)
);
}
}
Image.network()网络图片
Image.network('https://img0.baidu.com/it/u=4227008132,2843866888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1084',),
Image.asset()本地图片assets/images/*存放本地图片
flutter:
uses-material-design: true
# 设置图片路径
assets:
- assets/images/
- assets/images/2.0x/
- assets/images/3.0x/
Image.asset('assets/images/1.jpg',),
fit图片比例
child: Image.network(
'https://img0.baidu.com/it/u=4227008132,2843866888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1084',
fit: BoxFit.cover,
),
repeat重复显示
child: Image.network(
'https://img0.baidu.com/it/u=4227008132,2843866888&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=1084',
repeat: ImageRepeat.repeat,
),
DecorationImage()圆形图片(圆角)
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 2),
borderRadius: BorderRadius.circular(100),
// 在容器内添加图片
image: const DecorationImage(
image: AssetImage('assets/images/1.jpg',),
fit: BoxFit.cover
)
),
),
ClipOval()圆形图片
ClipOval(
child: Image.asset(
'assets/images/1.jpg',
width: 100,
height: 100,
fit: BoxFit.fill,
),
),
CircleAvatar()圆形图片(用于头像)
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 2),
borderRadius: BorderRadius.circular(100),
),
child: CircleAvatar(
radius: 100,
backgroundImage: AssetImage('assets/images/1.jpg'),
),
),
图标组件Icon
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// ----------------------- Icon -----------------------
body: Center(
child: Icon(
Icons.home,
size: 60,
color: Colors.blue,
),
)
);
// ---------------------------------------------------------
}
}
水平布局组件Row
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
// ----------------------- Row -----------------------
child: Row(
children: [
Text("1"),
Text("2"),
],
),
// ---------------------------------------------------------
)
);
}
}
垂直布局组件Column
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
// ----------------------- Column -----------------------
child: Column(
children: [
Text("1"),
Text("2"),
],
),
// ---------------------------------------------------------
)
);
}
}
弹性布局组件Flex和Expanded
纵向布局需要给一个外层容器,并且容器需要高度
Flex()flex布局-
direction布局方式
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"这里是顶部",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blue,
),
body: Column(
children: [
// ----------------------- Flex -----------------------
Flex(
direction: Axis.horizontal,
children: const [
// 占用比例
Expanded(
flex: 1,
child: Text('1', style: TextStyle(fontSize: 40),),
),
Expanded(
flex: 2,
child: Text('2', style: TextStyle(fontSize: 40),),
),
],
),
SizedBox(
width: 400,
height: 200,
child: Flex(
direction: Axis.vertical,
children: const [
// 占用比例
Expanded(
flex: 1,
child: Text('1', style: TextStyle(fontSize: 40),),
),
Expanded(
flex: 2,
child: Text('2', style: TextStyle(fontSize: 40),),
),
],
),
),
// ---------------------------------------------------------
],
)
);
}
}
分隔线组件Divider
color颜色thickness高度(厚度)height上下高度(上下边距)indent左侧缩进endIndent右侧缩进
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"这里是顶部",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blue,
),
body: Column(
children: const [
SizedBox(height: 10,),
// ------------------------ Divider ------------------------
Text("普通的分割线,默认样式"),
Divider(),
Text("指定颜色的分割线"),
Divider(color: Colors.orange,),
Text("指定高度的分割线"),
Divider(thickness: 5,),
Text("设置分割线上下高度(上下边距)"),
Divider(color: Colors.blue, height: 60,),
Text("前后缩进的分割线"),
Divider(color: Colors.red, indent: 40, endIndent: 40,),
// ---------------------------------------------------------
],
)
);
}
}
列表组件ListView
scrollDirection列表排列方式
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"这里是顶部",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blue,
),
// ------------------------ ListView ------------------------
body: ListView(
scrollDirection: Axis.vertical,
children: const [
Text("list1"),
Text("list2"),
Text("list3"),
Text("list4"),
Text("list5"),
],
)
// ---------------------------------------------------------
);
}
}
网格组件GridView
GridView.count()指定一行的个数GridView.extent()指定每个元素的宽度
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"这里是顶部",
style: TextStyle(
color: Colors.white
),
),
backgroundColor: Colors.blue,
),
// ------------------------ ListView ------------------------
body: GridView.count(
crossAxisCount: 4,
children: const [
Text("list1"),
Text("list2"),
Text("list3"),
Text("list4"),
Text("list5"),
Text("list6"),
],
)
// ---------------------------------------------------------
);
}
}
层叠组件Stack
Stack()层叠组件Positioned()定位
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
width: 200, // 宽
height: 200, // 高
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(color: Colors.black, width: 1), // 边框
),
// ----------------------- Stack -----------------------
child: Stack(
children: [
const Text("这是普通内容", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),),
// 定位
Positioned(
// top: 0,
// left: 0,
right: 40,
bottom: 40,
child: const Icon(Icons.home, color: Colors.orange, size: 40,),
),
// 对齐
Align(
alignment: Alignment.bottomRight,
child: const Icon(Icons.add_a_photo, color: Colors.red, size: 40,),
),
],
)
// ---------------------------------------------------------
),
),
);
}
}
布局组件AspectRatio
设置一个指定宽高比的容器
aspectRatio比例,例:aspectRatio: 3,宽:高 = 3:1
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// ----------------------- AspectRatio -----------------------
body: Column(
children: [
AspectRatio(
aspectRatio: 2,
child: Container(
color: Colors.lightBlue,
),
),
],
),
// ---------------------------------------------------------
);
}
}
卡片组件Card
margin外边距elevation设置阴影值的深度shadowColor阴影的颜色,默认是灰色colorshape圆角clipBehavior内容溢出的剪切方式child
class CardPage extends StatelessWidget {
const CardPage({super.key});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(10), // 外边距
elevation: 10, // 阴影
shadowColor: Colors.grey, // 阴影颜色
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: Column(
children: [
const ListTile(
leading: CircleAvatar(
radius: 40,
backgroundImage: AssetImage('assets/images/1.jpg'),
),
title: Text('123'),
subtitle: Text("456"),
),
Divider(indent: 10, endIndent: 10,),
const ListTile(
title: Text("简介:1111111111111111111"),
),
const ListTile(
title: Text("详情:2222222222222222222"),
)
],
),
);
}
}
按钮组件
ElevatedButton()普通按钮
ElevatedButton(onPressed: (){}, child: const Text("普通按钮")),
TextButton()文本按钮
TextButton(onPressed: (){}, child: const Text("文本按钮")),
OutlinedButton()边框按钮
OutlinedButton(onPressed: () {}, child: const Text("边框按钮")),
IconButton()图标按钮
IconButton(onPressed: (){}, icon: const Icon(Icons.add_a_photo)),
.icon()带图标的按钮
ElevatedButton.icon(
onPressed: (){},
label: Text("带图标的按钮"),
icon: Icon(Icons.add),
),
style修改样式-
backgroundColor按钮背景颜色
-
foregroundColor按钮文本颜色(优先级低于label)
ElevatedButton.icon(
onPressed: (){},
label: Text("带图标的按钮", style: TextStyle(color: Colors.white),),
icon: Icon(Icons.send, color: Colors.white,),
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.blue),
foregroundColor: WidgetStateProperty.all(Colors.black),
),
),
style圆角样式-
shape圆角
SizedBox(
height: 60,
child: ElevatedButton(
onPressed: (){},
style: ButtonStyle(
shape: WidgetStateProperty.all(
const CircleBorder()
)
),
child: const Text("圆角"),
),
),
- 修改边框按钮的边框
OutlinedButton(
onPressed: () {},
style: ButtonStyle(
side: WidgetStateProperty.all(
const BorderSide(width: 5, color: Colors.blue)
)
),
child: const Text("边框按钮")
),
- 按钮外加个容器,指定按钮大小
SizedBox(
width: 300,
height: 40,
child: ElevatedButton.icon(
onPressed: (){},
label: Text("大尺寸按钮"),
icon: Icon(Icons.add),
),
),
- 自适应尺寸按钮
Expanded(child: SizedBox(
width: 300,
height: 60,
child: ElevatedButton.icon(
onPressed: (){},
label: Text("自适应尺寸按钮"),
icon: Icon(Icons.add),
),
)),
容器组件Wrap
spacing组件间距runSpacing行间距alignment对齐方式
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("这里是顶部", style: TextStyle(color: Colors.white),),
backgroundColor: Colors.blue,
),
// ------------------------- Wrap -------------------------
body: Wrap(
spacing: 10, // 组件间距
runSpacing: 10, // 行间距
alignment: WrapAlignment.end, // 对齐方式
children: [
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
ElevatedButton(onPressed: () {}, child: const Text("边框按钮")),
],
),
// ---------------------------------------------------------
);
}
}
标题栏AppBar
title标题centerTitle标题居中leading左侧按钮actions右侧按钮automaticallyImplyLeading是否自动显示默认的返回按钮flexibleSpace可伸缩的空间,通常用于添加一些背景图像或效果bottom在标题下面显示的小部件,通常是一个选项卡栏或按钮组elevationAppBar 的阴影深度backgroundColor背景颜色brightness控制 AppBar 文字和图标的颜色主题iconTheme控制 AppBar 内部图标的颜色和大小textTheme控制 AppBar 内部文本的样式titleSpacing标题左右两侧的空间toolbarOpacity工具栏部分的透明度bottomOpacity底部部分的透明度
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("这里是顶部", style: TextStyle(color: Colors.white),), // 标题
centerTitle: true, // 标题居中
backgroundColor: Colors.blue, // 背景颜色
// 左侧按钮
leading: IconButton(onPressed: (){}, icon: Icon(Icons.west), style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(Colors.white),
),),
// 右侧按钮
actions: [
IconButton(onPressed: (){}, icon: Icon(Icons.search), style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(Colors.white)
),),
IconButton(onPressed: (){}, icon: Icon(Icons.more_horiz), style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(Colors.white)
),)
],
// 当页面滚动时,保证appBar的背景色不变
flexibleSpace: Container(color: Colors.blue),
),
);
}
}
底部导航栏,悬浮按钮
bottomNavigationBar底部导航栏floatingActionButton悬浮按钮
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int _currentIndex = 0;
final List<Widget> _tabPages = const [
HomePage(),
MessagePage(),
MyPage(),
];
// 切换tabBar
void _onTap(index) {
setState(() {
_currentIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
// appBar
appBar: AppBar(
title: Text('标题', style: TextStyle(color: Colors.white),),
centerTitle: true,
backgroundColor: Colors.blue,
),
// body
body: _tabPages[_currentIndex],
// tabBar
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
fixedColor: Colors.blue,
iconSize: 26,
type: BottomNavigationBarType.fixed,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: "首页"
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: "消息"
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
label: "我的"
),
],
onTap: _onTap,
),
// 悬浮按钮
floatingActionButton: Container(
width: 60,
height: 60,
padding: const EdgeInsets.all(2),
margin: const EdgeInsets.only(top: 6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
),
child: FloatingActionButton(
backgroundColor: _currentIndex == 1 ? Colors.blue : Colors.grey,
onPressed: () {
setState(() {
_currentIndex = 1;
});
},
child: Icon(Icons.add, color: Colors.white,),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
全局修改标题栏样式
theme设置全局标题栏样式-
color标题栏背景颜色
-
elevation标题栏阴影深度
-
centerTitle标题是否居中
-
titleTextStyle标题样式
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
// ----------------------- 全局标题栏样式 -----------------------
theme: ThemeData(
appBarTheme: const AppBarTheme(
color: Colors.blue, // 标题栏背景颜色
elevation: 4, // 标题栏阴影深度
centerTitle: true, // 标题是否居中
// 标题样式
titleTextStyle: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold
)
)
),
// ---------------------------------------------------------
home: HomePage(),
);
}
}
收缩侧边栏
drawer左侧边栏endDrawer右侧边栏-
Drawer()抽屉
-
UserAccountsDrawerHeader()默认头部布局
-
DrawerHeader()自定义头部布局
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("这是标题"),
),
body: Text("hello world"),
// ----------------------- 左边侧边栏 -----------------------
drawer: const Drawer(
child: Column(
children: [
UserAccountsDrawerHeader(
accountName: Text("左侧边栏"),
accountEmail: Text("e-mail"),
currentAccountPicture: CircleAvatar(
backgroundImage: AssetImage("assets/images/1.jpg"),
),
decoration: BoxDecoration(
color: Colors.lightBlue
),
),
ListTile(
title: Text("首页"),
leading: CircleAvatar(
backgroundColor: Colors.blue,
child: Icon(Icons.home, color: Colors.white,),
),
),
Divider(indent: 10, endIndent: 10,),
ListTile(
title: Text("消息"),
leading: CircleAvatar(
backgroundColor: Colors.blue,
child: Icon(Icons.message, color: Colors.white, ),
),
),
],
),
),
// ----------------------- 右边侧边栏 -----------------------
endDrawer: const Drawer(
child: Column(
children: [
DrawerHeader(
decoration: BoxDecoration(
color: Colors.lightBlue,
),
child: SizedBox(
width: double.infinity,
child: Text("右侧边栏", style: TextStyle(color: Colors.white),),
),
),
ListTile(
title: Text("我的"),
leading: CircleAvatar(
backgroundColor: Colors.blue,
child: Icon(Icons.message, color: Colors.white, ),
),
),
],
),
),
);
}
}
路由
原生太麻烦,直接使用第三方插件(官方推荐)
# 安装go_router
flutter pub add go_router
flutter pub add provider
pubspec.yaml
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
go_router: ^14.8.1
provider: ^6.1.4
main.dart主入口
import 'package:flutter/material.dart';
import 'package:flutter_app/providers/auth_provider.dart';
import 'package:provider/provider.dart';
void main() => runApp(
ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: const MyApp(),
)
);
// MyApp
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final authProvider = Provider.of<AuthProvider>(context);
final appRouter = AddRouter(authProvider);
return MaterialApp.router(
debugShowCheckedModeBanner: false,
routerConfig: appRouter.router,
);
}
}
lib/providers/auth_provider.dart全局状态管理
import 'package:flutter/cupertino.dart';
class AuthProvider extends ChangeNotifier {
bool _isLogin = false;
bool get isLogin => _isLogin;
void login() {
_isLogin = true;
notifyListeners(); // 通知监听器数据变化
}
void logOut() {
_isLogin = false;
notifyListeners(); // 通知监听器数据变化
}
}
lib/constants/route_names.dart路由名称常量
class RouteNames {
// 基础路由
static const home = '/';
static const notFound = '/404';
// 功能路由
static const message = '/message/:id';
static const my = '/my';
}
lib/routes/router.part路由文件
import 'package:flutter_app/constants/route_names.dart';
import 'package:flutter_app/providers/auth_provider.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_app/pages/404.dart';
import 'package:flutter_app/pages/home.dart';
import 'package:flutter_app/pages/message.dart';
import 'package:flutter_app/pages/my.dart';
class AddRouter {
final AuthProvider authProvider;
AddRouter(this.authProvider);
late final GoRouter router = GoRouter(
// 初始化路由
initialLocation: '/',
// 错误页面
errorBuilder: (context, state) => const NotFoundPage(),
// 路由守卫
// redirect: (BuildContext context, GoRouterState, state) {
// return null;
// }
routes: _routes
);
List<GoRoute> get _routes => [
GoRoute(
path: RouteNames.home,
name: RouteNames.home,
builder: (context, state) => HomePage(),
),
// path参数
GoRoute(
path: RouteNames.message,
name: RouteNames.message,
builder: (context, state) => MessagePage(
id: state.pathParameters['id']!,
),
),
// query参数
GoRoute(
path: RouteNames.my,
name: RouteNames.my,
builder: (context, state) => MyPage(
content: state.uri.queryParameters['content'] ?? ''
),
),
];
}
- 路由,传参
// path传参
context.pushNamed(RouteNames.message, pathParameters: {'id': '1123456'});
// query传参
context.pushNamed(RouteNames.my, queryParameters: {'content': '首页过来的!!!'});
- 接参
import 'package:flutter/material.dart';
class MessagePage extends StatefulWidget {
final String id; // 参数
const MessagePage({super.key, required this.id}); // 参数
@override
State<StatefulWidget> createState() {
return _HomePageState();
}
}
class _HomePageState extends State<MessagePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('消息', style: TextStyle(color: Colors.white),),
backgroundColor: Colors.blue,
),
// widget.id 使用参数
body: Center(
child: Text(widget.id, style: TextStyle(fontSize: 30),),
),
);
}
}
弹窗Dialog
showDialog()显示弹窗Navigator.pop(context);关闭弹窗
AlertDialog
AlertDialog()对话框类型的弹窗
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("这里是顶部", style: TextStyle(color: Colors.white),), // 标题
backgroundColor: Colors.blue, // 背景颜色
),
body: Center(
child: ElevatedButton(onPressed: (){
// ----------------------- AlertDialog -----------------------
showDialog(
barrierDismissible: true, // 点击遮罩弹窗是否消失
context: context,
builder: (context) {
return AlertDialog(
title: const Text("提示"),
content: const Text("这是一个弹窗......"),
actions: <Widget>[
TextButton(onPressed: (){
Navigator.pop(context); // 关闭弹窗
}, child: const Text("取消")),
TextButton(onPressed: () {
Navigator.pop(context); // 关闭弹窗
}, child: const Text("确认")),
],
);
}
);
// ---------------------------------------------------------
}, child: Text("dialog")),
),
);
}
}
SimpleDialog
SimpleDialog()选项列表的弹窗SimpleDialogOption()选项
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("这里是顶部", style: TextStyle(color: Colors.white),), // 标题
backgroundColor: Colors.blue, // 背景颜色
),
body: Center(
child: ElevatedButton(onPressed: (){
// ----------------------- SimpleDialog -----------------------
showDialog(
barrierDismissible: true, // 点击遮罩弹窗是否消失
context: context,
builder: (context) {
return SimpleDialog(
title: const Text("选择..."),
children: <Widget>[
SimpleDialogOption(
child: const Text("选项一"),
onPressed: () {
Navigator.pop(context);
},
),
SimpleDialogOption(
child: const Text("选项二"),
onPressed: () {
Navigator.pop(context);
},
),SimpleDialogOption(
child: const Text("选项三"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
);
// ---------------------------------------------------------
}, child: Text("dialog")),
),
);
}
}
Toast
没有内置组件,需要第三方插件
dependencies:
flutter:
sdk: flutter
fluttertoast: ^8.2.2
Fluttertoast.showToast()-
msg显示的内容
-
toastLength时长
-
gravity位置
-
timeInSecForIosWebios/web显示时长
-
backgroundColor背景颜色
-
textColor字体颜色
-
fontSize字体大小
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("这里是顶部", style: TextStyle(color: Colors.white),), // 标题
backgroundColor: Colors.blue, // 背景颜色
),
body: Center(
child: ElevatedButton(onPressed: (){
// ------------------------- Toast -------------------------
Fluttertoast.showToast(
msg: "hello world",
toastLength: Toast.LENGTH_SHORT, // 时长
gravity: ToastGravity.BOTTOM, // 位置
timeInSecForIosWeb: 3, // ios/web显示时长
backgroundColor: Colors.grey, // 背景颜色
textColor: Colors.white, // 字体颜色
fontSize: 30, // 字体大小
);
// ---------------------------------------------------------
}, child: Text("Toast")),
),
);
}
}
PageView
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// ------------------------- PageView -------------------------
body: Center(
// child: PageView(
// children: [
// HomePage(),
// MessagePage(id: 'message page',),
// MyPage(content: 'my page')
// ],
// ),
child: PageView.builder(
itemCount: 3,
itemBuilder: (BuildContext context, int index) {
return MessagePage(id: 'message ${index + 1}',);
},
),
)
// ---------------------------------------------------------
);
}
}
组件传参
- 父组件
body: Center(
child: MessagePage(id: '1',),
)
- 子组件
- 类中接收
widget.id子类中使用
class MessagePage extends StatefulWidget {
final String id; // 接收
const MessagePage({super.key, required this.id});
@override
State<StatefulWidget> createState() {
return _HomePageState();
}
}
class _HomePageState extends State<MessagePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('消息', style: TextStyle(color: Colors.white),),
backgroundColor: Colors.blue,
),
body: Center(
// 使用
child: Text(widget.id, style: TextStyle(fontSize: 30),),
),
);
}
}