flutter学习笔记

65 阅读2分钟

flutter学习笔记

环境安装

组件

我的网站

项目目录结构

  • lib/ 包含Dart代码,是应用程序的核心目录。通常会包含一个名为main.dart的文件,该文件是应用程序的入口点。主要在这个目录中实现App的主要功能
  • android/ 包含Android原生代码和配置文件,例如gradle文件、AndroidManifest.xml等。在这个目录中可以进行Android原生相关的配置和自定义,例如添加自定义的Gradle插件或者添加第三方库等
  • ios/ 包含iOS原生代码和配置文件,例如Xcode项目文件、Info.plist等。在这个目录中可以进行iOS原生相关的配置和自定义,例如添加自定义的CocoaPods依赖或者添加第三方库等
  • test/ 包含应用程序的测试代码,通常使用Flutter自带的测试框架进行单元测试和集成测试
  • pubspec.yaml 应用程序的依赖和配置文件,其中包含了应用程序所依赖的第三方库的名称、版本以及其他配置信息
  • web web目录是Flutter项目的Web平台代码目录,用于在Web平台上运行Flutter应用程序
  • windows windows目录是Flutter项目的Windows平台代码目录,用于在Windows平台上运行Flutter应用程序

hello world

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

容器组件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

文本组件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

  • SizedBoxContainer 在布局方面的作用是很相似的
  • 只设置尺寸,用 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

布局组件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

图片组件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

分隔线组件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

卡片组件Card

  • margin 外边距
  • elevation 设置阴影值的深度
  • shadowColor 阴影的颜色,默认是灰色
  • color
  • shape 圆角
  • 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 在标题下面显示的小部件,通常是一个选项卡栏或按钮组
  • elevation AppBar 的阴影深度
  • 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 位置
    • timeInSecForIosWeb ios/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),),
      ),
    );
  }
}