Flutter Scaffold 页面结构

Material是一套设计风格,提供了大量的小部件,这里用Material风格搭建一个常见的应用页面结构。

创建Material应用

import 'package:flutter/material.dart';

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 关闭debug条幅
      home: Center(
        child: Text("首页"),
      ),
    );
  }
}

这里实例化的MaterialApp,而不是一般的Center Widget。

使用图表 Icon

import 'package:flutter/material.dart';

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 关闭debug条幅
      home: Center(
        child: Icon(
          Icons.star,
          color: Colors.amber,
          size: 128,
        ),
      ),
    );
  }
}


这里用到了Icon
所有Icons:https://fonts.google.com/icons
1

使用按钮 ElevatedButton

Flutter 提供了多种按钮小部件,这里ElevatedButton以为例。

import 'package:flutter/material.dart';

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 关闭debug条幅
      home: Center(
          child: ElevatedButton(
              onPressed: () {
                print("点击了按钮!");
              },
              child: Text("一个按钮"))),
    );
  }
}

1

切换主题

定义两个主题样式

在app/themes/app_theme.dart下定义两个主题样式:一个浅色,一个深色。

import 'package:flutter/material.dart';

class AppTheme {
  static ThemeData light = ThemeData(
      primaryColor: Colors.deepPurpleAccent,
      colorScheme: ColorScheme.light(
        primary: Colors.deepPurpleAccent,
        secondary: Colors.amber,
      ));
  static ThemeData dark = ThemeData(
      primaryColor: Colors.deepPurpleAccent,
      colorScheme: ColorScheme.dark(
        primary: Colors.cyan,
        secondary: Colors.amber,
      ));
}

调用主题样式

用MaterialApp的theme和darkTheme分别调用浅色和深色主题样式。

import 'package:flutter/material.dart';
import 'package:package_name/app/themes/app_theme.dart';

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 关闭debug条幅
      theme: AppTheme.light,
      darkTheme: AppTheme.dark,
      home: Center(
          child: ElevatedButton(
              onPressed: () {
                print("点击了按钮!");
              },
              child: Text("一个按钮"))),
    );
  }
}

在IOS的设置-开发者里设置深色外观:
1
1

Scaffold 页面结构

使用Scaffold小部件可以得到一个Material风格的页面结构,可以设置页面头部工具栏、页面主体、页面底部的导航栏、侧边抽屉、底部侧板、浮动按钮等。

import 'package:flutter/material.dart';

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: DefaultTabController(
          // 设置默认Tab控制器
          length: 2,
          child: Scaffold(
            backgroundColor: Colors.amber,
            // 页面主体
            body: TabBarView(children: [
              Icon(
                Icons.explore_outlined,
                size: 128,
                color: Colors.black12,
              ),
              Icon(
                Icons.local_fire_department,
                size: 128,
                color: Colors.black12,
              ),
            ]),
            appBar: AppBar(
              title: Text("页面标题"),
              leading: IconButton(
                  onPressed: () {
                    print("这是导航菜单");
                  },
                  icon: Icon(Icons.menu)),
              actions: [
                IconButton(
                    onPressed: () {
                      print("这是Action位置");
                    },
                    icon: Icon(Icons.more_horiz))
              ],
              bottom: TabBar(tabs: [
                // 设置标签栏
                Tab(
                  text: 'Tab1',
                ),
                Tab(
                  text: 'Tab2',
                )
              ]),
            ),
            bottomNavigationBar: BottomNavigationBar(items: [
              BottomNavigationBarItem(
                  icon: Icon(Icons.explore_outlined), label: "发现"),
              BottomNavigationBarItem(
                  icon: Icon(Icons.add_a_photo_outlined), label: "添加"),
              BottomNavigationBarItem(
                  icon: Icon(Icons.account_circle_outlined), label: "用户")
            ]),
          ),
        ));
  }
}

Scaffold
如果是VSCode编辑器,在StatelessWidget上按快捷键Ctrl/Command+.,执行Convert to StatefulWidget命令,可以把无状态小部件转换成有状态小部件。

import 'package:flutter/material.dart';

class App extends StatefulWidget {
  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  
  Widget build(BuildContext context) {
    return MaterialApp(}
}

有状态小部件多出一个_AppState状态类,用于管理状态,通过createState、setState来创建和设置状态。

激活底部导航

import 'package:flutter/material.dart';

class App extends StatefulWidget {
  
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {
  int currentAppBottomNavigationBarItem = 0;
  void onTabAppBottomNavigationBarItem(int index) {
    setState(() {
      currentAppBottomNavigationBarItem = index;
    });
  }

  
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: DefaultTabController(
          // 设置默认Tab控制器
          length: 2,
          child: Scaffold(
            backgroundColor: Colors.amber,
            // 页面主体
            body: TabBarView(children: [
              Icon(
                Icons.explore_outlined,
                size: 128,
                color: Colors.black12,
              ),
              Icon(
                Icons.local_fire_department,
                size: 128,
                color: Colors.black12,
              ),
            ]),
            appBar: AppBar(
              title: Text("页面标题"),
              leading: IconButton(
                  onPressed: () {
                    print("这是导航菜单");
                  },
                  icon: Icon(Icons.menu)),
              actions: [
                IconButton(
                    onPressed: () {
                      print("这是Action位置");
                    },
                    icon: Icon(Icons.more_horiz))
              ],
              bottom: TabBar(tabs: [
                // 设置标签栏
                Tab(
                  text: 'Tab1',
                ),
                Tab(
                  text: 'Tab2',
                )
              ]),
            ),
            bottomNavigationBar: BottomNavigationBar(
                currentIndex: currentAppBottomNavigationBarItem,
                onTap: onTabAppBottomNavigationBarItem,
                items: [
                  BottomNavigationBarItem(
                      icon: Icon(Icons.explore_outlined), label: "发现"),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.add_a_photo_outlined), label: "添加"),
                  BottomNavigationBarItem(
                      icon: Icon(Icons.account_circle_outlined), label: "用户")
                ]),
          ),
        ));
  }
}

1

点击底部导航,切换显示小部件

  final pageMain = [
    TabBarView(children: [
      Icon(
        Icons.explore_outlined,
        size: 128,
        color: Colors.black12,
      ),
      Icon(
        Icons.local_fire_department,
        size: 128,
        color: Colors.black12,
      ),
    ]),
    Center(
      child: Icon(
        Icons.add_a_photo_outlined,
        size: 128,
        color: Colors.black12,
      ),
    ),
    Center(
      child: Icon(
        Icons.account_circle_outlined,
        size: 128,
        color: Colors.black12,
      ),
    )
  ];

首先定义三个小部件列表,然后在body里按照索引来调用。

body: pageMain.elementAt(currentAppBottomNavigationBarItem),

1

动态显示或隐藏AppBar

用showAppBar来决定是否显示appBar。

class _AppState extends State<App> {
  // 是否显示应用栏
  bool showAppBar = true;

  int currentAppBottomNavigationBarItem = 0;
  void onTabAppBottomNavigationBarItem(int index) {
    setState(() {
      currentAppBottomNavigationBarItem = index;
      // 第一个显示,其他不显示
      showAppBar = index == 0;
    }
appBar: showAppBar ? AppBar(...) : null,

appBar设置为null,就是隐藏。

FloatingActionButton 漂浮动作按钮

floatingActionButton: FloatingActionButton(
onPressed: () {
  print('这是漂浮动作按钮。');
},
child: Icon(Icons.share_outlined),
backgroundColor: Colors.black,
foregroundColor: Colors.white,
)

用Scaffold的floatingActionButton参数,可以设置漂浮动作按钮。

定义部件

上面的小部件都是放在一起,我们还可以把一些把页面的部分小部件单独放到一个文件里,这里以appBar为例:

app_page_header.dart

import 'package:flutter/material.dart';

class AppPageHeader extends StatelessWidget implements PreferredSizeWidget {
  
  final Size preferredSize = Size.fromHeight(100);
  
  Widget build(BuildContext context) {
    return AppBar(
      title: Text("页面标题"),
      leading: IconButton(
          onPressed: () {
            print("这是导航菜单");
          },
          icon: Icon(Icons.menu)),
      actions: [
        IconButton(
            onPressed: () {
              print("这是Action位置");
            },
            icon: Icon(Icons.more_horiz))
      ],
      bottom: TabBar(tabs: [
        // 设置标签栏
        Tab(
          text: 'Tab1',
        ),
        Tab(
          text: 'Tab2',
        )
      ]),
    );
  }
}

这里单独定义了一个AppPageHeader的类,作为appBar,然后我们就可以调用它了。

import 'package:package_name/app/components/app_page_header.dart';

appBar: showAppBar ? AppPageHeader() : null,

BottomSheet 底部面板

这里点击浮动按钮显示底部面板,把浮动按钮单独封装成了一个单独的文件app_floating_action_button.dart:

import 'package:flutter/material.dart';

class AppFloatingActionButton extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: () {
        print('这是漂浮动作按钮。');
        showBottomSheet(
          context: context,
          builder: (BuildContext context) {
            return SizedBox.expand(
              child: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    const Text('漂浮动作按钮'),
                    ElevatedButton(
                      child: const Text('关闭'),
                      onPressed: () => Navigator.pop(context),
                    ),
                  ],
                ),
              ),
            );
          },
        );
      },
      child: Icon(Icons.share_outlined),
      backgroundColor: Colors.black,
      foregroundColor: Colors.white,
    );
  }
}

调用:

floatingActionButton: AppFloatingActionButton(),

1

边栏抽屉

import 'package:flutter/material.dart';

class AppPageAside extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Drawer(
      child: Center(
        child: Text("边栏抽屉"),
      ),
    );
  }
}

在Scaffold函数里用drawer参数调用:

drawer: AppPageAside(),

1

AppBar leading 位置显示抽屉

onPressed: () {
  Scaffold.of(context).openDrawer();
},

设置边栏抽屉显示的内容

import 'package:flutter/material.dart';

class AppPageAside extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Drawer(
      child: Center(
        child: ListView(
          padding: EdgeInsets.zero,
          children: [
            UserAccountsDrawerHeader(
                accountName: Text("姓名"), accountEmail: Text("abc@domain.com")),
            ListTile(
              title: Text(
                "评论",
                textAlign: TextAlign.right,
              ),
              trailing: Icon(Icons.comment_outlined),
            ),
            ListTile(
              title: Text(
                "账户",
                textAlign: TextAlign.right,
              ),
              trailing: Icon(Icons.account_box_outlined),
            ),
            ListTile(
              title: Text(
                "退出",
                textAlign: TextAlign.right,
              ),
              trailing: Icon(Icons.logout_outlined),
            ),
          ],
        ),
      ),
    );
  }
}

1

弹出菜单

import 'package:flutter/material.dart';

class AppPageHeaderActionsMore extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return PopupMenuButton(
      itemBuilder: (context) => [
        PopupMenuItem(
          value: 'stack',
          child: Icon(
            Icons.view_agenda_outlined,
            color: Colors.black12,
          ),
        ),
        PopupMenuItem(
          value: 'stack',
          child: Icon(
            Icons.dashboard_outlined,
            color: Colors.black12,
          ),
        ),
      ],
      icon: Icon(Icons.more_horiz),
      offset: Offset(0, 50),
      onCanceled: () {
        print("弹出菜单按钮");
      },
      onSelected: (value) {
        print("弹出菜单按钮的值是 $value");
      },
    );
  }
}

AppBar(
......
    actions: [
    AppPageHeaderActionsMore(),
    ]
......

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/964146.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2月3日星期一今日早报简报微语报早读

2月3日星期一&#xff0c;农历正月初六&#xff0c;早报#微语早读。 1、多个景区发布公告&#xff1a;售票数量已达上限&#xff0c;请游客合理安排行程&#xff1b; 2、2025春节档总票房破70亿&#xff0c;《哪吒之魔童闹海》破31亿&#xff1b; 3、美宣布对中国商品加征10…

大模型本地化部署(Ollama + Open-WebUI)

文章目录 环境准备下载Ollama模型下载下载Open-WebUI 本地化部署的Web图形化界面本地模型联网查询安装 Docker安装 SearXNG本地模型联网查询 环境准备 下载Ollama 下载地址&#xff1a;Ollama网址 安装完成后&#xff0c;命令行里执行命令 ollama -v查看是否安装成功。安装成…

10 Flink CDC

10 Flink CDC 1. CDC是什么2. CDC 的种类3. 传统CDC与Flink CDC对比4. Flink-CDC 案例5. Flink SQL 方式的案例 1. CDC是什么 CDC 是 Change Data Capture&#xff08;变更数据获取&#xff09;的简称。核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数…

【25考研】南开软件考研复试复习重点!

一、复试内容 复试采取现场复试的方式。复试分为笔试、机试和面试三部分。三部分合计100分&#xff0c;其中笔试成绩占30%、机试成绩占30%、面试成绩占40%。 1.笔试&#xff1a;专业综合基础测试 考核方式&#xff1a;闭卷考试&#xff0c;时长为90分钟。 笔试考查内容范围…

【Cadence仿真技巧学习笔记】求解65nm库晶体管参数un, e0, Cox

在设计放大器的第一步就是确定好晶体管参数和直流工作点的选取。通过阅读文献&#xff0c;我了解到L波段低噪声放大器的mos器件最优宽度计算公式为 W o p t . p 3 2 1 ω L C o x R s Q s p W_{opt.p}\frac{3}{2}\frac{1}{\omega LC_{ox}R_{s}Q_{sp}} Wopt.p​23​ωLCox​Rs…

【leetcode练习·二叉树拓展】归并排序详解及应用

本文参考labuladong算法笔记[拓展&#xff1a;归并排序详解及应用 | labuladong 的算法笔记] “归并排序就是二叉树的后序遍历”——labuladong 就说归并排序吧&#xff0c;如果给你看代码&#xff0c;让你脑补一下归并排序的过程&#xff0c;你脑子里会出现什么场景&#xff…

[ESP32:Vscode+PlatformIO]新建工程 常用配置与设置

2025-1-29 一、新建工程 选择一个要创建工程文件夹的地方&#xff0c;在空白处鼠标右键选择通过Code打开 打开Vscode&#xff0c;点击platformIO图标&#xff0c;选择PIO Home下的open&#xff0c;最后点击new project 按照下图进行设置 第一个是工程文件夹的名称 第二个是…

Docker 部署教程jenkins

Docker 部署 jenkins 教程 Jenkins 官方网站 Jenkins 是一个开源的自动化服务器&#xff0c;主要用于持续集成&#xff08;CI&#xff09;和持续交付&#xff08;CD&#xff09;过程。它帮助开发人员自动化构建、测试和部署应用程序&#xff0c;显著提高软件开发的效率和质量…

MySQL锁类型(详解)

锁的分类图&#xff0c;如下&#xff1a; 锁操作类型划分 读锁 : 也称为共享锁 、英文用S表示。针对同一份数据&#xff0c;多个事务的读操作可以同时进行而不会互相影响&#xff0c;相互不阻塞的。 写锁 : 也称为排他锁 、英文用X表示。当前写操作没有完成前&#xff0c;它会…

《苍穹外卖》项目学习记录-Day11销量排名统计

销量排名需要查两张表&#xff0c;一张是order_detail&#xff0c;它里面有number字段&#xff0c;这个字段体现了商品的销售的份数。我们仅仅查这一张表是不够的&#xff0c;因为用户下单了&#xff0c;下单了之后就会产生订单数据和对应的订单详情数据&#xff0c;假设他下完…

走向基于大语言模型的新一代推荐系统:综述与展望

HightLight 论文题目&#xff1a;Towards Next-Generation LLM-based Recommender Systems: A Survey and Beyond作者机构&#xff1a;吉林大学、香港理工大学、悉尼科技大学、Meta AI论文地址&#xff1a; https://arxiv.org/abs/2410.1974 基于大语言模型的下一代推荐系统&…

Vue3学习笔记-模板语法和属性绑定-2

一、文本插值 使用{ {val}}放入变量&#xff0c;在JS代码中可以设置变量的值 <template><p>{{msg}}</p> </template> <script> export default {data(){return {msg: 文本插值}} } </script> 文本值可以是字符串&#xff0c;可以是布尔…

python算法和数据结构刷题[5]:动态规划

动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种算法思想&#xff0c;用于解决具有最优子结构的问题。它通过将大问题分解为小问题&#xff0c;并找到这些小问题的最优解&#xff0c;从而得到整个问题的最优解。动态规划与分治法相似&#xff0c;但区别在于动态…

【阅读笔记】New Edge Diected Interpolation,NEDI算法,待续

一、概述 由Li等提出的新的边缘指导插值(New Edge—Di-ected Interpolation&#xff0c;NEDI)算法是一种具有良好边缘保持效果的新算法&#xff0c;它利用低分辨率图像与高分辨率图像的局部协方差问的几何对偶性来对高分辨率图像进行自适应插值。 2001年Xin Li和M.T. Orchard…

C++ Primer 迭代器

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

DeepSeek R1 简易指南:架构、本地部署和硬件要求

DeepSeek 团队近期发布的DeepSeek-R1技术论文展示了其在增强大语言模型推理能力方面的创新实践。该研究突破性地采用强化学习&#xff08;Reinforcement Learning&#xff09;作为核心训练范式&#xff0c;在不依赖大规模监督微调的前提下显著提升了模型的复杂问题求解能力。 技…

直方图:摄影中的视觉数据指南

目录 一、直方图基础&#xff1a;揭开它的神秘面纱 二、解读直方图类型&#xff1a;亮度与色彩的密码 &#xff08;一&#xff09;亮度直方图 &#xff08;二&#xff09;RGB 直方图 三、拍摄中巧用直方图&#xff1a;优化曝光与效果 &#xff08;一&#xff09;精准判断曝…

力扣动态规划-19【算法学习day.113】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.矩形中移动的最大次数 题目链接…

树莓派pico入坑笔记,睡眠

关于树莓派pico和circuitpython的更多玩法&#xff0c;请看树莓派pico专栏 关于在 CircuitPython 中使用警报和浅/深度睡眠的更多信息&#xff0c;请参阅此学习指南。 树莓派pico支持浅睡眠和深度睡眠&#xff0c;其中深度睡眠唤醒后将从boot.py开始运行 支持按时间唤醒和引…

【蓝桥杯】日志统计

日志统计&#xff08;编程题&#xff09;https://dashoj.com/d/lqbproblem/p/53https://dashoj.com/d/lqbproblem/p/53https://dashoj.com/d/lqbproblem/p/53 题目 日志统计(编程题) 讲解 这个讲解感觉比较通俗易懂。 蓝桥杯2018年省赛B组08&#xff08;c/c&#xff09;日…