【Flutter】有状态组件StatefulWidget&Scaffold组件属性

🔥 本文由 程序喵正在路上 原创,优快云首发!
💖 系列专栏:Flutter学习
🌠 首发时间:2024年5月26日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾

有状态组件StatefulWidget

Flutter 中自定义组件其实就是一个类,这个类需要继承 StatelessWidget / StatefulWidget

  • StatelessWidget 是无状态组件,状态不可变的 widget
  • StatefulWidget 是有状态组件,持有的状态可能在 widget 生命周期改变
  • 通俗的讲:如果我们想改变页面中的数据的话,这个时候就需要用到 StatefulWidget

实现计数器功能

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _numCount = 0; //计数

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("flutter App"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              "$_numCount",
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 60),
            ElevatedButton(
                onPressed: () {
                  setState(() {
                    _numCount++;
                  });
                },
                child: const Text("增加"))
          ],
        ),
      ),
      //Scaffold组件中自带的浮动按钮
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _numCount++;
          });
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

在使用 StatefulWidget 后,建议我们代码的框架写成上面这样,将 Scaffold 组件写到自定义组件中,这样我们可以使用其在有状态组件中的一些属性

在这里插入图片描述

实现动态列表

需求:实现通过点击按钮就能添加列表项的效果

class _HomePageState extends State<HomePage> {
  final List<String> _list = []; //final修饰的列表可以增加元素

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("动态列表"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _list.add("我是一个新增的列表");
          });
        },
        child: const Icon(Icons.add),
      ),
      body: ListView(
        children: _list.map((e) {
          return ListTile(
            title: Text(e),
          );
        }).toList(),
      ),
    );
  }
}

在这里插入图片描述

Scaffold属性:BottomNavigationBar

组件介绍

BottomNavigationBar 是底部导航条,可以让我们定义底部 Tab 切换,bottomNavigationBarScaffold 组件的参数。

BottomNavigationBar 常见的属性

属性名说明
itemsList 底部导航条按钮集合
iconSizeicon
currentIndex默认选中第几个
onTap选中变化回调函数
fixedColor选中的颜色
type底部超过4个菜单必须配置这个属性:ButtomNavigationBarType.fixedButtomNavigationBarType.shifting

自定义底部导航

实现如下效果:

在这里插入图片描述

class _HomePageState extends State<HomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("自定义底部导航"),
      ),
      body: const Center(child: Text("我是一个文本")),
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
        ],
      ),
    );
  }
}

底部菜单选中

前面自定义的底部导航还没有完整实现,一般要求我们点击哪个菜单,哪个菜单就会显示选中的效果,下面我们来实现这个效果

在这里插入图片描述

class _HomePageState extends State<HomePage> {
  int _currentIndex = 0; //当前选中索引

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("自定义底部导航"),
      ),
      body: const Center(child: Text("我是一个文本")),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        fixedColor: Colors.blue,
        onTap: (value) {
          setState(() {
            _currentIndex = value;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
        ],
      ),
    );
  }
}

自定义底部导航实现页面切换

为了让代码条理更加清晰,我们将每个页面分文件写。

lib 目录下新建目录 pages,在 pages 下新建文件 tabs.dart 和文件夹 tabs,在 tabs 下新建 3 个页面对应的文件:

在这里插入图片描述

home.dart

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  
  Widget build(BuildContext context) {
    return const Center(
      child: Text("首页"),
    );
  }
}

category.dart

import 'package:flutter/material.dart';

class CategoryPage extends StatefulWidget {
  const CategoryPage({super.key});

  
  State<CategoryPage> createState() => _CategoryPageState();
}

class _CategoryPageState extends State<CategoryPage> {
  
  Widget build(BuildContext context) {
    return const Center(
      child: Text("分类"),
    );
  }
}

setting.dart

import 'package:flutter/material.dart';

class SettingPage extends StatefulWidget {
  const SettingPage({super.key});

  
  State<SettingPage> createState() => _SettingPageState();
}

class _SettingPageState extends State<SettingPage> {
  
  Widget build(BuildContext context) {
    return const Center(
      child: Text("系统设置"),
    );
  }
}

tabs.dart:前面页面切换的代码

import 'package:flutter/material.dart';
import './tabs/home.dart';
import './tabs/category.dart';
import './tabs/setting.dart';

class Tabs extends StatefulWidget {
  const Tabs({super.key});

  
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  int _currentIndex = 0; //当前选中索引
  final List<Widget> _pages = const [
    HomePage(),
    CategoryPage(),
    SettingPage(),
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("自定义底部导航"),
      ),
      body: _pages[_currentIndex], //自动切换页面
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        fixedColor: Colors.blue,
        onTap: (value) {
          setState(() {
            _currentIndex = value;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
        ],
      ),
    );
  }
}

main.dart

import 'package:flutter/material.dart';
import 'pages/tabs.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      home: const Tabs(),
    );
  }
}

在这里插入图片描述

Scaffold属性:FloatingActionButton

FloatingActionButton详解

FloatingActionButton 简称 FAB ,可以实现浮动按钮,也可以实现类似闲鱼app的底部凸起导航

属性名称属性值
child子视图,一般为 Icon,不推荐使用文字
tooltipFAB被长按时显示,也是无障碍功能
backgroundColor背景颜色
elevation未点击时的阴影
highlightElevation点击时阴影值,默认12
onPressed点击事件回调
shape可以定义FAB的形状等
mini是否为 mini 类型,默认为 false

实现类似闲鱼App底部导航凸起按钮

我们在前面自定义底部导航的代码稍加修改,再添加一个浮动按钮即可实现类似闲鱼底部导航效果:

在这里插入图片描述

这里给出 tabs.dart 的代码,其中 message.dartuser.dart 两个页面内容和其他页面类似

import 'package:flutter/material.dart';
import './tabs/home.dart';
import './tabs/category.dart';
import './tabs/setting.dart';
import './tabs/message.dart';
import './tabs/user.dart';

class Tabs extends StatefulWidget {
  const Tabs({super.key});

  
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  int _currentIndex = 0; //当前选中索引
  final List<Widget> _pages = const [
    HomePage(),
    CategoryPage(),
    MessagePage(),
    SettingPage(),
    UserPage(),
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("浮动按钮"),
      ),
      body: _pages[_currentIndex], //自动切换页面
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _currentIndex,
        fixedColor: Colors.blue,
        onTap: (value) {
          setState(() {
            _currentIndex = value;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.message), label: "消息"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
          BottomNavigationBarItem(icon: Icon(Icons.people), label: "用户")
        ],
      ),
      floatingActionButton: Container(
        height: 60,
        width: 60,
        padding: const EdgeInsets.all(4),
        margin: const EdgeInsets.only(top: 4),
        decoration: BoxDecoration(
            color: Colors.white, borderRadius: BorderRadius.circular(30)),
        child: FloatingActionButton(
          shape: const CircleBorder(),
          backgroundColor:
              _currentIndex == 2 ? Colors.yellowAccent : Colors.blueAccent,
          onPressed: () {
            setState(() {
              _currentIndex = 2;
            });
          },
          child: const Icon(Icons.add),
        ),
      ),
      floatingActionButtonLocation:
          FloatingActionButtonLocation.centerDocked, //浮动按钮位置
    );
  }
}

Scaffold属性:抽屉菜单Drawer

Scaffold 组件里面传入 drawer 参数可以定义左侧边栏,传入 endDrawer 可以定义右侧边栏。侧边栏默认是隐藏的,我们可以通过手指滑动显示侧边栏,也可以通过点击按钮显示侧边栏。

DrawerHeader

DrawerHeader 是侧边栏的头部,常见属性如下:

属性描述
decoration设置顶部背景颜色
child配置子元素
padding内边距
margin外边距

在上一节代码 tabs.dart 的基础上,我们来给页面添加侧边栏

class _TabsState extends State<Tabs> {
  int _currentIndex = 0; //当前选中索引
  final List<Widget> _pages = const [
    HomePage(),
    CategoryPage(),
    MessagePage(),
    SettingPage(),
    UserPage(),
  ];

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("浮动按钮"),
      ),
      //左侧边栏
      drawer: Drawer(
        child: Column(
          children: [
            DrawerHeader(
              decoration: const BoxDecoration(
                  color: Colors.blueAccent,
                  image: DecorationImage(
                      image: NetworkImage(
                          "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/1.jpg"),
                      fit: BoxFit.cover)),
              child: ListView(
                children: const [
                  ListTile(
                    leading: CircleAvatar(
                      backgroundImage: NetworkImage(
                          "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/2.jpg"),
                    ),
                    title: Text(
                      "嘻嘻",
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                  ),
                  ListTile(
                    title: Text(
                      "Email: 123456@qq.com",
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            const ListTile(
              leading: CircleAvatar(child: Icon(Icons.people)),
              title: Text("个人中心"),
            ),
            const Divider(),
            const ListTile(
              leading: CircleAvatar(child: Icon(Icons.settings)),
              title: Text("系统设置"),
            )
          ],
        ),
      ),
      //右侧侧边栏
      endDrawer: Drawer(
        child: Column(
          children: [
            DrawerHeader(
              decoration: const BoxDecoration(
                  color: Colors.blueAccent,
                  image: DecorationImage(
                      image: NetworkImage(
                          "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/3.jpg"),
                      fit: BoxFit.cover)),
              child: ListView(
                children: const [
                  ListTile(
                    leading: CircleAvatar(
                      backgroundImage: NetworkImage(
                          "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/4.jpg"),
                    ),
                    title: Text(
                      "嘻嘻",
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                  ),
                  ListTile(
                    title: Text(
                      "Email: 123456@qq.com",
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            const ListTile(
              leading: CircleAvatar(child: Icon(Icons.people)),
              title: Text("个人中心"),
            ),
            const Divider(),
            const ListTile(
              leading: CircleAvatar(child: Icon(Icons.settings)),
              title: Text("系统设置"),
            )
          ],
        ),
      ),
      body: _pages[_currentIndex], //自动切换页面
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _currentIndex,
        fixedColor: Colors.blue,
        onTap: (value) {
          setState(() {
            _currentIndex = value;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(icon: Icon(Icons.category), label: "分类"),
          BottomNavigationBarItem(icon: Icon(Icons.message), label: "消息"),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
          BottomNavigationBarItem(icon: Icon(Icons.people), label: "用户")
        ],
      ),
      floatingActionButton: Container(
        height: 60,
        width: 60,
        padding: const EdgeInsets.all(4),
        margin: const EdgeInsets.only(top: 4),
        decoration: BoxDecoration(
            color: Colors.white, borderRadius: BorderRadius.circular(30)),
        child: FloatingActionButton(
          shape: const CircleBorder(),
          backgroundColor:
              _currentIndex == 2 ? Colors.yellowAccent : Colors.blueAccent,
          onPressed: () {
            setState(() {
              _currentIndex = 2;
            });
          },
          child: const Icon(Icons.add),
        ),
      ),
      floatingActionButtonLocation:
          FloatingActionButtonLocation.centerDocked, //浮动按钮位置
    );
  }
}

左右侧边栏只是名称不同,其他组件的使用都是一致的

在这里插入图片描述

在这里插入图片描述

UserAccountsDrawerHeader

像前面这样我们自己写侧边栏的头部内容,还是比较麻烦的,而且样式也不好调整,为此 flutter 给我们提供了 UserAccountsDrawerHeader 组件,其常用属性如下:

属性描述
decoration设置顶部背景颜色
accountName账户名称
accountEmail账户邮箱
currentAccountPicture用户头像
otherAccountsPictures用来设置当前账户其他账户头像
margin外边距

接下来,我们用 来写一个侧边栏

//左侧边栏
drawer: Drawer(
  child: Column(
    children: [
      UserAccountsDrawerHeader(
        accountName: const Text("嘻嘻"),
        accountEmail: const Text("123456@qq.com"),
        currentAccountPicture: const CircleAvatar(
          backgroundImage: NetworkImage(
              "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/1.jpg"),
        ),
        decoration: const BoxDecoration(
          color: Colors.blue,
          image: DecorationImage(
              image: NetworkImage(
                  "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/2.jpg"),
              fit: BoxFit.cover),
        ),
        otherAccountsPictures: [
          Image.network(
              "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/3.jpg"),
          Image.network(
              "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/4.jpg"),
          Image.network(
              "https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/5.jpg"),
        ],
      ),
      const ListTile(
        leading: CircleAvatar(child: Icon(Icons.people)),
        title: Text("个人中心"),
      ),
      const Divider(),
      const ListTile(
        leading: CircleAvatar(child: Icon(Icons.settings)),
        title: Text("系统设置"),
      )
    ],
  ),
),

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序喵正在路上

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值