Flutter Travel
main.dart
createState()
作用
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
// 新版本的写法
State<MyApp> createState() => _MyAppState();
createState() 方法是 Flutter 中 StatefulWidgets 的一部分,它的作用是创建与该 StatefulWidget 关联的状态对象。具体来说:
createState() 方法返回一个状态对象(在这个例子中是 _MyAppState),这个状态对象保存了可能在 widget 生命周期内变化的数据。
每个 StatefulWidget 都需要有一个对应的状态类(如这里的 _MyAppState),用于管理 widget 的状态。
使用 _MyAppState 对 MyApp 进行管理。
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false, //去掉右上角的debug标签
title: Constants.appName,
theme: Constants.lightTheme,
darkTheme: Constants.darkTheme, // Constants是定义在const.dart文件中的类用于管理静态资源
home: MainScreen(),
);
}
}
MaterialApp: 是 Flutter 中的一个顶层 widget,提供了 Material Design 的视觉结构和行为。它通常作为应用的根 widget。
home: MainScreen(): 指定了应用的主页面(即启动时显示的第一个页面)。MainScreen 是一个自定义的 widget,表示应用的主要界面。
main_screen.dart
App的主界面。
树状结构如下:
class _MainScreenState extends State<MainScreen> {
late PageController _pageController; // late PageController _pageController: 声明了一个 PageController 对象,用于控制 PageView 的页面切换。late 关键字表示该变量会在第一次使用前被初始化。
int _page = 0; // 定义了一个名为 _page 的整数变量,用于记录当前页面的索引。初始值为 0。
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView( // PageView 是一个用于显示多个页面的控件,它将多个子控件排列成一个滚动视图。
physics: NeverScrollableScrollPhysics(), // physics: NeverScrollableScrollPhysics(): 设置了 PageView 的滚动行为,使其无法滚动。NeverScrollableScrollPhysics() 是一个滚动行为,它不允许滚动。
controller: _pageController, // 将 PageController 对象绑定到 PageView 上,用于控制 PageView 的页面切换。
onPageChanged: onPageChanged, // 定义了一个回调函数,当页面切换时触发。
children: List.generate(4, (index) => Home()), // 生成 4 个 Home() 控件,用于显示主页面。
),
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisSize: MainAxisSize.max, // 设置了 BottomAppBar 的宽度为最大值,即填充整个屏幕。
mainAxisAlignment: MainAxisAlignment.spaceBetween, // 设置了 BottomAppBar 的主轴对齐方式为从两端对齐。
children: <Widget>[
SizedBox(width: 7.0),
barIcon(icon: Icons.home, page: 0),
barIcon(icon: Icons.favorite, page: 1),
barIcon(icon: Icons.mode_comment, page: 2, badge: true),
barIcon(icon: Icons.person, page: 3),
SizedBox(width: 7.0),
],
),
color: Theme.of(context).primaryColor,
),
);
}
PageView
详细介绍
List.generate(4, (index) => Home())
List.generate() 函数是一个方便的工具,用于创建具有指定长度的列表,其元素由一个函数动态生成。该函数以索引为参数,返回列表中该特定位置的元素值。
这里的作用就是创建了4个列表都指向了Home()界面。如果有别的界面children可以写成如下:
class AppNavigation extends StatefulWidget {
const AppNavigation({super.key});
@override
State<AppNavigation> createState() => _AppNavigationState();
}
class _AppNavigationState extends State<AppNavigation> {
int _index = 0;
final PageController _ctrl = PageController();
final List<MenuData> menus = const [
MenuData(label: '猜数字', icon: Icons.question_mark),
MenuData(label: '电子木鱼', icon: Icons.my_library_music_outlined),
MenuData(label: '白板绘制', icon: Icons.palette_outlined),
MenuData(label: '网络文章', icon: Icons.article_outlined),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: _buildContent(),
bottomNavigationBar: AppBottomBar(
currentIndex: _index,
onItemTap: _onChangePage, // 点击底部导航栏的回调函数
menus: menus, // 底部导航栏的菜单数据,直接读取List里的数据不然也可以自己写一个list就像那个上面那样
),
);
}
void _onChangePage(int index) {
_ctrl.jumpToPage(index);
setState(() {
_index = index; // 更新当前选中的索引定位到index索引下的界面
});
}
Widget _buildContent() {
return PageView(
physics: const NeverScrollableScrollPhysics(),
controller: _ctrl,
children: const [ //这里的部分就是等价于 List.generate(4, (index) => Home())的功能
GuessPage(),
MuyuPage(),
Paper(),
NetArticlePage(),
],
);
}
}
bottomNavigationBar
bottomNavigationBar: 是 Scaffold 的一个属性,用于指定应用底部的导航栏。
BottomAppBar: 是一个位于屏幕底部的工具栏 widget,通常用于放置导航栏图标、按钮或其他交互元素。
BottomAppBar: 是一个 Material Design 风格的底部工具栏。
child: 是 BottomAppBar 的子 widget,用于定义底部工具栏的内容。
color: 设置底部工具栏的颜色。在这个例子中,颜色设置为 Theme.of(context).primaryColor,即应用的主题主要颜色。
页面跳转功能
void navigationTapped(int page) {
_pageController.jumpToPage(page);
}
@override
void initState() {
super.initState();
_pageController = PageController();
}
@override
void dispose() {
super.dispose();
_pageController.dispose();
}
void onPageChanged(int page) {
setState(() {
this._page = page;
});
}
Widget barIcon(
{IconData icon = Icons.home, int page = 0, bool badge = false}) { //花括号里的为默认参数,根据传入的参数改变
return IconButton(
icon: badge ? IconBadge(icon: icon, size: 24.0) : Icon(icon, size: 24.0),
color: _page == page
? Theme.of(context).colorScheme.secondary
: Colors.blueGrey[300],
onPressed: () => _pageController.jumpToPage(page), // 点击图标时,切换到对应页面
);
}
}
home.dart
appBar: AppBar(
actions: <Widget>[ // actions: <Widget> 是 AppBar 组件的一个属性,用于定义应用栏中显示的操作按钮或图标。这里指代的
//notifications_none 图标
IconButton( //调用IconBage方法初始化图标
icon: IconBadge(
icon: Icons.notifications_none,
size: 22.0,
color: Colors.blueGrey[300]!, //参数
),
onPressed: () {},
),
],
),
body: ListView( // ListView小部件,用于在屏幕上垂直排列多个子小部件。下面是对每一部分的详细解释:
children: <Widget>[ //children:这是一个包含多个子小部件的列表。每个子小部件将按顺序垂直排列在ListView中
Padding(
padding: EdgeInsets.all(20.0), //用于为子小部件添加内边距(即四周的空白区域)。这里设置了所有方向的内边距为20.0。
child: Text(
"Where are you \ngoing?",
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.w600,
),
),
),
Padding(
padding: EdgeInsets.all(20.0),
child: custom.SearchBar(), //定义自定义的搜索栏组件,并添加到ListView中由于和flutter自带的SearchBar组件冲突,所以这里使用自定义的组件名字custom
),
buildHorizontalList(context), //调用buildHorizontalList方法初始化横向列表,context参数
buildVerticalList(),
],
),
buildHorizontalList(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10.0, left: 20.0),
height: 250.0,
width: MediaQuery.of(context).size.width, //MediaQuery.of(context)可以获取设备的屏幕尺寸、方向等信息,这对于响应式布局非常有用。
child: ListView.builder( // ListView.builder:这是一个高效的方式创建动态长度的列表,只有可见的项会被构建。特别适合处理大量数据。
scrollDirection: Axis.horizontal, //scrollDirection: Axis.horizontal:设置列表滚动方向为水平方向。
primary: false, //表示这个 ListView 不是主轴上的主要滚动视图。这通常用于防止与页面中的其他滚动行为冲突。
itemCount: places == null ? 0 : places.length, // 获取列表项的数量。如果places为空,则返回0,否则返回places的长度。
itemBuilder: (BuildContext context, int index) {
Map place = places.reversed.toList()[index]; //将 places 列表反转后转换为新列表,并获取索引为 index 的元素。
//这确保了列表项从最后-个到第一个显示。
return HorizontalPlaceItem(place: place); //调用HorizontalPlaceItem组件,并传入place参数
},
),
);
}
horizontal_place_item.dart
return Padding(
padding: const EdgeInsets.only(right: 20.0),
child: InkWell(
child: Container(
height: 250.0,
width: 140.0,
child: Column(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.asset(
"${place["img"]}",
height: 178.0,
width: 140.0,
fit: BoxFit.cover,
),
),
SizedBox(height: 7.0),
Container(
alignment: Alignment.centerLeft,
child: Text(
"${place["name"]}",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 10.0,
),
maxLines: 2,
textAlign: TextAlign.left,
),
),
SizedBox(height: 5.0),
Container(
alignment: Alignment.centerLeft,
child: Text(
"${place["location"]}",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 13.0,
color: Colors.blueGrey[300],
),
maxLines: 1,
textAlign: TextAlign.left,
),
),
],
),
),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return Details(); //页面跳转
},
),
);
},
),
);
InkWell
解释
InkWell
是 Flutter 中一个非常常用的小部件,用于实现点击反馈效果(通常称为“墨水涟漪”效果)。它通常与 Material
小部件一起使用,以提供符合 Material Design 规范的交互体验。以下是 InkWell
的详细解释:
1. 基本概念
- 作用:
InkWell
提供了点击、长按等手势的视觉反馈,类似于按下按钮时出现的涟漪效果。 - 特点:
- 可以嵌套在其他小部件中,如
Container
、Card
或Row
等。 - 支持多种手势,包括点击、长按、双击等。
- 提供自定义的反馈颜色和形状。
- 可以嵌套在其他小部件中,如
2. 主要属性
onTap
:点击事件回调函数。onDoubleTap
:双击事件回调函数。onLongPress
:长按事件回调函数。splashColor
:点击时的涟漪颜色,默认为当前主题的高亮颜色。highlightColor
:按下时的高亮颜色,默认为透明。borderRadius
:设置涟漪效果的圆角半径。customBorder
:自定义涟漪效果的边界形状,例如圆形或矩形。child
:InkWell
包裹的子小部件,通常是需要添加点击反馈的元素。
3. 示例代码
import 'package:flutter/material.dart';
class MyInkWellExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('InkWell Example'),
),
body: Center(
child: InkWell(
onTap: () {
// 处理点击事件
print('Tapped');
},
onLongPress: () {
// 处理长按事件
print('Long Pressed');
},
splashColor: Colors.blue, // 设置点击时的涟漪颜色
highlightColor: Colors.red.withOpacity(0.5), // 设置按下时的高亮颜色
borderRadius: BorderRadius.circular(8.0), // 设置圆角半径
child: Container(
width: 200,
height: 100,
alignment: Alignment.center,
child: Text(
'Tap or Long Press Me',
style: TextStyle(fontSize: 16.0),
),
),
),
),
);
}
}
4. 应用场景
- 按钮:为普通容器或文本添加点击反馈效果,使其看起来像按钮。
- 卡片:为
Card
小部件添加点击反馈,增强交互体验。 - 列表项:为
ListView
中的每个列表项添加点击反馈,方便用户操作。
5. 注意事项
-
必须包裹在
Material
中:InkWell
需要有一个Material
小部件作为其祖先,否则不会显示涟漪效果。如果你发现没有效果,可以尝试将InkWell
包裹在一个Material
小部件中。Material( child: InkWell( // ... ), )
-
避免过度使用:虽然
InkWell
提供了很好的交互反馈,但过多的使用可能会导致界面显得过于复杂,影响用户体验。
总结
InkWell
是 Flutter 中用于实现点击反馈效果的重要小部件,特别适合于需要符合 Material Design 规范的应用。通过合理使用 InkWell
,你可以为应用中的各种交互元素添加直观且美观的点击反馈,提升用户体验。
Navigator.of(context).push
解释
Navigator.of(context).push 是 Flutter 中用于导航到新页面(路由)的方法。它允许你在应用中实现页面之间的跳转,并且可以传递数据给目标页面。下面是对它的详细解释:
- 基本概念
Navigator:Flutter 的导航管理器,用于管理页面堆栈(即路由)。每个 Navigator 都维护一个页面堆栈,支持页面的推送(push)和弹出(pop)操作。
of(context):通过 BuildContext 获取当前上下文中的 Navigator 实例。context 提供了对小部件树位置的引用,确保你可以在正确的位置进行导航。 - push 方法
作用:将一个新的路由(页面)推入导航堆栈,显示新的页面并保留之前的页面。
返回值:返回一个 Future,当用户从新页面返回时,这个 Future 会完成,并返回从新页面传递回来的数据(如果有)。 - 常用参数
Route:表示要推送的新路由。通常使用 MaterialPageRoute 或 CupertinoPageRoute 来创建新页面的路由。
Navigator.of(context).push 是 Flutter 中用于导航到新页面的主要方法。它允许你推送新路由到导航堆栈,并且可以传递数据给新页面或从新页面返回数据。合理使用 Navigator 和 push 方法,可以帮助你构建流畅且功能丰富的页面导航体验。
Navigator.of(context).pop
解释
Navigator.of(context).pop 是 Flutter 中用于从导航堆栈中弹出当前页面的方法。它允许用户返回到前一个页面,并可以选择传递数据回前一个页面。下面是对其详细解释:
- 基本概念
作用:从导航堆栈中移除当前页面,返回到前一个页面。
返回值:可以传递一个可选的返回值(通常是 dynamic 类型),该值可以在前一个页面中通过 await Navigator.of(context).push(...) 获取。
details.dart
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context), //返回上一页
),
)
children: <Widget>[
SizedBox(height: 10),
buildSlider(), // 构建滑动图片,可以调用函数实现
SizedBox(height: 20),
ListView(
padding: EdgeInsets.symmetric(horizontal: 20),
primary: false,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
......
buildSlider() {
return Container(
padding: EdgeInsets.only(left: 20),
height: 250.0,
child: ListView.builder(
scrollDirection: Axis.horizontal, // 设置水平滚动
primary: false, // 关闭默认滚动
itemCount: places == null ? 0 : places.length,
itemBuilder: (BuildContext context, int index) {
Map place = places[index];
return Padding(
padding: EdgeInsets.only(right: 10.0),
child: ClipRRect( //ClipRRect 是 Flutter 中用于将子小部件裁剪为圆角矩形的类。它允许你为图像、容器等小部件添加圆角效果,确保其内容不会超出指定的边界。
borderRadius: BorderRadius.circular(10.0),
child: Image.asset( //静态资源调用(记得yaml配置)
"${place["img"]}",
height: 250.0,
width: MediaQuery.of(context).size.width - 40.0, // 获取屏幕宽度
fit: BoxFit.cover,
),
),
);
},
),
);
}
EdgeInsets
解释
EdgeInsets
是 Flutter 中用于定义内边距(padding)或外边距(margin)的类。它允许你精确控制四个方向(上、下、左、右)的间距。以下是 EdgeInsets
的详细解释及其常用属性:
1. 基本概念
- 作用:
EdgeInsets
用于为小部件添加内边距或外边距,确保子小部件与周围的其他元素之间有一定的间距。 - 特点:提供了多种构造函数和静态方法,方便快速创建不同类型的边距。
2. 常用属性和构造函数
2.1 EdgeInsets.all(double value)
- 作用:为所有四个方向(上、下、左、右)设置相同的边距。
- 示例:
EdgeInsets.all(16.0) // 上、下、左、右都设置为16.0逻辑像素
2.2 EdgeInsets.symmetric({vertical: double, horizontal: double})
- 作用:分别设置垂直方向(上和下)和水平方向(左和右)的边距。
- 参数:
vertical
:设置上下边距。horizontal
:设置左右边距。
- 示例:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0)
2.3 EdgeInsets.only({left, top, right, bottom})
- 作用:为每个方向单独设置边距。
- 参数:
left
:设置左边距。top
:设置上边距。right
:设置右边距。bottom
:设置下边距。
- 示例:
EdgeInsets.only(left: 10.0, top: 20.0, right: 10.0, bottom: 5.0)
2.4 EdgeInsets.fromLTRB(double left, double top, double right, double bottom)
- 作用:按顺序分别为左、上、右、下四个方向设置边距。
- 示例:
EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 5.0)
3. 常用场景
- 内边距 (
Padding
小部件):为子小部件添加内边距,确保其与周围元素有一定的间距。 - 外边距 (
Container
或SizedBox
小部件):为小部件添加外边距,调整其在父容器中的位置。
4. 示例代码
import 'package:flutter/material.dart';
class PaddingExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Padding Example'),
),
body: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(16.0),
child: Text('All sides 16.0'),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Text('Symmetric padding'),
),
Padding(
padding: EdgeInsets.only(left: 10.0, top: 20.0, right: 10.0, bottom: 5.0),
child: Text('Custom padding'),
),
Padding(
padding: EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 5.0),
child: Text('LTRB padding'),
),
],
),
);
}
}
5. 注意事项
- 单位:
EdgeInsets
的值是以逻辑像素为单位的,通常与屏幕密度无关。 - 性能:使用
EdgeInsets.only
或EdgeInsets.symmetric
可以提高代码的可读性和维护性,避免硬编码多个方向的边距值。 - 响应式布局:结合
MediaQuery.of(context).size
可以根据屏幕尺寸动态调整边距,实现响应式布局。
总结
EdgeInsets
是 Flutter 中用于定义内边距或外边距的类,提供了多种构造函数和静态方法,方便灵活地设置不同方向的边距。通过合理使用 EdgeInsets
,你可以更好地控制小部件之间的间距,提升应用的布局效果。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述