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的主界面。
树状结构如下:
img

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

img

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 提供了点击、长按等手势的视觉反馈,类似于按下按钮时出现的涟漪效果。
  • 特点
    • 可以嵌套在其他小部件中,如 ContainerCardRow 等。
    • 支持多种手势,包括点击、长按、双击等。
    • 提供自定义的反馈颜色和形状。

2. 主要属性

  • onTap:点击事件回调函数。
  • onDoubleTap:双击事件回调函数。
  • onLongPress:长按事件回调函数。
  • splashColor:点击时的涟漪颜色,默认为当前主题的高亮颜色。
  • highlightColor:按下时的高亮颜色,默认为透明。
  • borderRadius:设置涟漪效果的圆角半径。
  • customBorder:自定义涟漪效果的边界形状,例如圆形或矩形。
  • childInkWell 包裹的子小部件,通常是需要添加点击反馈的元素。

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. 注意事项

  • 必须包裹在 MaterialInkWell 需要有一个 Material 小部件作为其祖先,否则不会显示涟漪效果。如果你发现没有效果,可以尝试将 InkWell 包裹在一个 Material 小部件中。

    Material(
      child: InkWell(
        // ...
      ),
    )
    
  • 避免过度使用:虽然 InkWell 提供了很好的交互反馈,但过多的使用可能会导致界面显得过于复杂,影响用户体验。

总结

InkWell 是 Flutter 中用于实现点击反馈效果的重要小部件,特别适合于需要符合 Material Design 规范的应用。通过合理使用 InkWell,你可以为应用中的各种交互元素添加直观且美观的点击反馈,提升用户体验。

Navigator.of(context).push 是 Flutter 中用于导航到新页面(路由)的方法。它允许你在应用中实现页面之间的跳转,并且可以传递数据给目标页面。下面是对它的详细解释:

  1. 基本概念
    Navigator:Flutter 的导航管理器,用于管理页面堆栈(即路由)。每个 Navigator 都维护一个页面堆栈,支持页面的推送(push)和弹出(pop)操作。
    of(context):通过 BuildContext 获取当前上下文中的 Navigator 实例。context 提供了对小部件树位置的引用,确保你可以在正确的位置进行导航。
  2. push 方法
    作用:将一个新的路由(页面)推入导航堆栈,显示新的页面并保留之前的页面。
    返回值:返回一个 Future,当用户从新页面返回时,这个 Future 会完成,并返回从新页面传递回来的数据(如果有)。
  3. 常用参数
    Route:表示要推送的新路由。通常使用 MaterialPageRoute 或 CupertinoPageRoute 来创建新页面的路由。

Navigator.of(context).push 是 Flutter 中用于导航到新页面的主要方法。它允许你推送新路由到导航堆栈,并且可以传递数据给新页面或从新页面返回数据。合理使用 Navigator 和 push 方法,可以帮助你构建流畅且功能丰富的页面导航体验。

Navigator.of(context).pop 是 Flutter 中用于从导航堆栈中弹出当前页面的方法。它允许用户返回到前一个页面,并可以选择传递数据回前一个页面。下面是对其详细解释:

  1. 基本概念
    作用:从导航堆栈中移除当前页面,返回到前一个页面。
    返回值:可以传递一个可选的返回值(通常是 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 小部件):为子小部件添加内边距,确保其与周围元素有一定的间距。
  • 外边距 (ContainerSizedBox 小部件):为小部件添加外边距,调整其在父容器中的位置。

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.onlyEdgeInsets.symmetric 可以提高代码的可读性和维护性,避免硬编码多个方向的边距值。
  • 响应式布局:结合 MediaQuery.of(context).size 可以根据屏幕尺寸动态调整边距,实现响应式布局。

总结

EdgeInsets 是 Flutter 中用于定义内边距或外边距的类,提供了多种构造函数和静态方法,方便灵活地设置不同方向的边距。通过合理使用 EdgeInsets,你可以更好地控制小部件之间的间距,提升应用的布局效果。

总结

posted on   爱吐水的小火龙  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示