Flutter第十四弹 抽屉菜单效果

news2024/11/28 3:10:39

目标:

1.怎么构建抽屉菜单效果?

2.抽屉菜单怎么定制?

一、抽屉菜单

侧滑抽屉菜单效果

1.1 抽屉菜单入口

Flutter 的脚手架Scaffold,默认提供了抽屉菜单效果入口。

主页面采用一个简单的页面,侧滑菜单首先使用一个Image,先看看侧滑效果。 

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:myflutter/drawer/widget/main_drawer.dart';

void main() => runApp(DrawerApp());

/**
 * 构建抽屉菜单APP
 *
 * @author zhouronghua
 * @time 2024/6/20 上午9:47
 */
class DrawerApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("抽屉菜单"),
        ),
        drawer: Drawer(
          /// 自定义抽屉菜单Widget
          child: MainDrawer(),
        ),
        body: new MainPage(),
      ),
    );
  }
}

/**
 * 主页面
 *
 * @author zhouronghua
 * @time 2024/6/20 上午10:02
 */
class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 主页面简单一个容器
    return Container(
      child: Text("我是主页面"),
    );
  }
}

显示效果:

 1.2 定制抽屉菜单

抽屉菜单显示用户未登录状态,允许用户点击,点击跳转登录页。

添加用户头像Header,和收藏菜单项

import 'package:flutter/material.dart';

class MainDrawer extends StatefulWidget {
  @override
  _MainDrawerState createState() {
    return _MainDrawerState();
  }
}

class _MainDrawerState extends State<MainDrawer> {
  /// 用户名:标记用户是否登录
  late String _userName;

  @override
  Widget build(BuildContext context) {
    // 顶部用户信息
    Widget userHeader = DrawerHeader(
        decoration: BoxDecoration(
          color: Colors.orangeAccent,
        ),
        child: InkWell(
          /// 纵向视图
          child: Column(
            /// 设置内边距
            children: [
              Padding(
                padding: EdgeInsets.only(bottom: 20.0),
                // 采用一个圆形图像
                child: CircleAvatar(
                  backgroundImage: AssetImage('assets/images/logo.png'),
                  /// 设置图片半径
                  radius: 40.0,
                ),
              ),
              Text("请先登录", style: TextStyle(fontSize: 20.0)),
            ],
          ),
        ));

    return ListView(
      // 列表项子项
      children: [
        /// 用户头
        userHeader,
        /// 收藏
        InkWell(
          onTap: () => {},
          child: ListTile(
            leading: Icon(Icons.favorite),
            title: Text('收藏列表', style: TextStyle(fontSize: 16.0)),
          ),
        ),
      ],
    );
  }
}

 

assets的图像可能加载不出来。

怎么解决呢?

1.2.1 解决assets图片加载不出来

添加assets图片,需要注册一下图片。

1)注册图片资源

在项目pubspec.yaml 中,将需要使用的图片进行注册

2)引用图片

路径就是 assets/图片路径。

                // 采用一个圆形图像
                child: CircleAvatar(
                  backgroundImage: AssetImage('assets/images/logo.png'),
                  /// 设置图片半径
                  radius: 40.0,
                ),

热重载项目,可以看到图片已经加载出来了。

1.3 抽屉菜单点击事件监听

InkWell 对应的点击事件:onTap

点击用户头像,如果没有登录,则导航跳转登录页面。

 // 顶部用户信息
    Widget userHeader = DrawerHeader(
        decoration: BoxDecoration(
          color: Colors.orangeAccent,
        ),
        child: InkWell(
          /// 点击事件
          onTap: () {
            /// 点击跳转登录页面
            if (_userName == null) {
              /// 用户未登录跳转登录页面
              Navigator.push(context, MaterialPageRoute(builder: (context) {
                return LoginPage();
              }));
              debugPrint("open login page");
            }
          },

          /// 纵向视图
          child: Column(
            /// 设置内边距
            children: [
              Padding(
                padding: EdgeInsets.only(bottom: 20.0),
                // 采用一个圆形图像
                child: CircleAvatar(
                  backgroundImage: AssetImage('assets/images/logo.png'),
                  /// 设置图片半径
                  radius: 40.0,
                ),
                // child: ClipRRect(
                //   borderRadius: BorderRadius.circular(40.0),
                //   child: Image.network(
                //     'http://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280',
                //     fit: BoxFit.cover,
                //   ),
                // ),
              ),
              Text("请先登录", style: TextStyle(fontSize: 20.0)),
            ],
          ),
        ));

二、用户登录页面

用户登录页,输入用户名+密码。

2.1 Form表单

Flutter提供了表单组件,可以定制表单内容。

 登录需要输入用户名,输入密码,以及登录按钮,因此可以采用一个列表结构展示。


import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {
  @override
  LoginPageState createState() {
    return LoginPageState();
  }
}

class LoginPageState extends State<LoginPage> {
  final _formKey = GlobalKey<FormState>();
  FocusNode _pwdNode = new FocusNode();
  late String? _username = null, _password = null;
  bool _isObscure = true;
  late Color? _pwdIconColor = null;


  @override
  void dispose() {
    _pwdNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("登录"),
        ),
        body: Form(
            key: _formKey,
            child: ListView(
              padding: EdgeInsets.symmetric(horizontal: 22.0),
              children: <Widget>[
                _buildUserName(),
                _buildPwd(),
                _buildLogin(),
                _buildRegister(),
              ],
            )));
  }

  Widget _buildRegister() {
    return Padding(
      padding: EdgeInsets.only(top: 10.0),
      child: Row(
        ///孩子居中对齐
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text('没有账号?'),
          GestureDetector(
            child: Text(
              '点击注册',
              style: TextStyle(color: Colors.green),
            ),
            onTap: () async {
              ///进入注册
              // Navigator.push(context, MaterialPageRoute(builder: (_) {
              //   return RegisterPage();
              // }));
            },
          ),
        ],
      ),
    );
  }

  Widget _buildLogin() {
    return Container(
      height: 45.0,
      margin: EdgeInsets.only(top: 18.0, left: 8.0, right: 8.0),
      child: RaisedButton(
        child: Text(
          '登录',
          style: TextStyle(fontSize: 18.0, color: Colors.white),
        ),
        color: Theme.of(context).primaryColor,
        onPressed: _doLogin,
      ),
    );
  }

  Widget _buildPwd() {
    return TextFormField(
      focusNode: _pwdNode,
      ///是否隐藏
      obscureText: _isObscure,
      validator: (String? value) {
        if (value?.trim().isEmpty == true) {
          return '请输入密码';
        }
        _password = value;
      },
      textInputAction: TextInputAction.done,
      onEditingComplete: _doLogin,
      decoration: InputDecoration(
          labelText: '密码',

          ///输入框尾部图标
          suffixIcon: IconButton(
              icon: Icon(
                Icons.remove_red_eye,
                color: _pwdIconColor,
              ),
              onPressed: () {
                setState(() {
                  _isObscure = !_isObscure;

                  ///密码隐藏 图标颜色控制
                  _pwdIconColor = (_isObscure
                      ? Colors.grey
                      : Theme.of(context).iconTheme.color)!;
                });
              })),
    );
  }

  Widget _buildUserName() {
    return TextFormField(
      autofocus: true,
      decoration: InputDecoration(
        labelText: '用户名',
      ),
      initialValue: _username,
      /// 从注册返回username
      ///设置键盘回车为下一步
      textInputAction: TextInputAction.next,
      onEditingComplete: () {
        ///点击下一步
        FocusScope.of(context).requestFocus(_pwdNode);
      },
      validator: (String? value) {
        if (value?.trim().isEmpty == true) {
          return '请输入用户名';
        }
        _username = value;
      },
    );
  }

  void _doLogin() async {
    _pwdNode.unfocus();

    ///输入的内容通过验证
    if (_formKey.currentState?.validate() == true) {
      //TODO 执行登录方法
      // var result = await Api.login(_username, _password);
      // if (result['errorCode'] == -1) {
      //   Toast.show(result['errorMsg'], context,
      //       duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
      // } else {
      //   AppManager.eventBus.fire(LoginEvent(_username));
      //   Navigator.pop(context);
      // }
    }
  }
}

2.2 输入框 

用户名是一个输入框,采用 TextFormField 控件。

  Widget _buildUserName() {
    return TextFormField(
      autofocus: true,
      decoration: InputDecoration(
        labelText: '用户名',
      ),
      initialValue: _username,
      /// 从注册返回username
      /// 设置键盘回车为下一步
      textInputAction: TextInputAction.next,
      onEditingComplete: () {
        /// 软键盘点击下一步
        FocusScope.of(context).requestFocus(_pwdNode);
      },
      validator: (String? value) {
        if (value?.trim().isEmpty == true) {
          return '请输入用户名';
        }
        _username = value;
      },
    );
  }

2.2.1 属性说明 

  •  autofocus:是否自动获得焦点
  • decoration:控件修饰。创建用于的边框、标签、图标和样式的束
    装饰“材质设计”文本字段。
  • initialValue:输入框初始值
  • textInputAction:设置键盘回车为下一步
  • onEditingComplete:编辑完成时的回调。软件盘点击下一步进入密码输入框获得焦点
  • validator:表单字段有效性校验。如果的内容为空的话,提示“请输入用户名”。点击“登录”的时候,校验输入的用户名内容。这个相当于输入内容的校验逻辑。return 返回的就是错误提示内容。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三星与SK海力士:以混合键合技术引领3D DRAM革新之路

在高速缓存内存&#xff08;HBM&#xff09;领域持续领跑的三星与SK海力士&#xff0c;正以混合键合技术为突破口&#xff0c;开启3D DRAM技术的新纪元。这一战略转型不仅预示着存储技术的深度革新&#xff0c;更体现了两大半导体巨头在提高集成度、优化性能与成本上的不懈追求…

【计算机网络篇】数据链路层(11)在数据链路层扩展以太网

文章目录 &#x1f354;使用网桥在数据链路层扩展以太网&#x1f95a;网桥的主要结构和基本工作原理&#x1f388;网桥的主要结构&#x1f50e;网桥转发帧的例子&#x1f50e;网桥丢弃帧的例子&#x1f50e;网桥转发广播帧的例子 &#x1f95a;透明网桥&#x1f50e;透明网桥的…

图论——代码随想录打卡

1 DFS深度搜索算法 深度优先搜索算法是从一个方向去进行搜索&#xff0c;直到遇到走不下去的终点&#xff0c;再进行回溯更换方向&#xff0c;重新进行搜索。因此有回溯也就意味着存在递归&#xff1a; void dfs(参数&#xff09;{处理节点dfs(图&#xff0c;选择的节点)回溯…

Hi3861 OpenHarmony嵌入式应用入门--0.96寸液晶屏 iic驱动ssd1306

使用iic驱动ssd1306&#xff0c;代码来源hihope\hispark_pegasus\demo\12_ssd1306 本样例提供了一个HarmonyOS IoT硬件接口的SSD1306 OLED屏驱动库&#xff0c;其功能如下&#xff1a; 内置了128*64 bit的内存缓冲区&#xff0c;支持全屏刷新;优化了屏幕刷新速率&#xff0c;…

AI发展核心要素之一(算力)

背景&#xff1a; 当今时代&#xff0c;云计算、人工智能、视频会议、短视频和各种社交媒体等行业蓬勃兴起&#xff0c;而ChatGPT-OpenAI的一次又一次的版本更新和迭代更是将我们带入了AI时代的新纪元。在2023年底的华为全联接大会上&#xff0c;孟晚舟就曾在演讲中表示:“算力…

云计算【第一阶段(17)】账号和权限管理

目录 一、用户账号和组账号概述 1.1、用户账号的三种角色 1.2、组账号的两个角色 二、用户账号文件 2.1、/etc/passwd 2.2、/etc/shadow 2.3、chage 命令 三、组账号文件 3.1、/etc/group 3.2、/etc/gshadow 四、添加组账户 4.1、添加删除组成员 4.2、删除组账号 …

北航数据结构与程序设计查找与排序编程题

查找与排序编程题 单词查找&#xff08;查找——基本题&#xff09;排座位&#xff08;简&#xff09;a 单词查找&#xff08;查找——基本题&#xff09; 【问题描述】 从标准输入中读入一个英文单词及查找方式&#xff0c;在一个给定的英文常用单词字典文件dictionary3000.…

Maven 和 Gradle 构建工具的基本使用

Maven和Gradle是Java生态系统中最常用的构建工具&#xff0c;它们不仅能简化项目的构建过程&#xff0c;还能帮助管理项目依赖、打包、发布等任务。本文将详细介绍如何掌握Maven和Gradle的基本使用&#xff0c;帮助开发者快速上手并应用于实际项目中。 一、Maven 1.1 什么是M…

第三方软件测试机构流程分享,软件检测报告需多少时间和费用?

第三方软件测试机构是区别于软件开发方和需求方的第三者存在&#xff0c;是专门为客户提供全方位软件测试服务的第三方检测机构。测试流程经过精心设计和不断优化&#xff0c;以确保客户的软件品质得到有效保障&#xff0c;那么第三方软件测试机构的基本测试流程具体有哪些呢?…

一套二开版微交易系统 香港十大贵金属交易平台 贵金属交易平台 贵金属交易app下载 微盘交易系统

一套二开前端UI得贵金属微交易系统&#xff0c;前端产品后台可任意更换 此系统框架不是以往的至尊的框架&#xff0c;系统完美运行&#xff0c;K线采用nodejs方式运行 源码使用起来非常流畅&#xff0c;不像至尊卡成翔 源码下载&#xff1a;https://download.csdn.net/downl…

Macbook pro插硬盘没反应,Macbook pro移动硬盘读不了怎么办

为了弥补Macbook pro硬盘容量的缺失&#xff0c;我们有时候会使用到外接硬盘或移动硬盘。一般来说&#xff0c;这些硬盘都是即插即用的&#xff0c;可能部分要安装插件。不过&#xff0c;在一些特殊情况下&#xff0c;也会遇到插硬盘没反应等问题。本文会给大家解答Macbook pro…

Linux——ansible关于“文件操作”的模块

修改文件并将其复制到主机 一、确保受管主机上存在文件 使用 file 模块处理受管主机上的文件。其工作方式与 touch 命令类似&#xff0c;如果不存在则创建一个空文件&#xff0c;如果存在&#xff0c;则更新其修改时间。在本例中&#xff0c;除了处理文件之外&#xff0c;Ansi…

Excel中插入的图片在不同电脑上消失的问题及解决方法

在使用Excel时插入图片&#xff0c;然后在不同电脑上打开却发现图片消失并被替换为链接地址&#xff0c;这个问题通常出现于文件中的图片路径没有正确保存或者电脑上缺少相关的图片文件。下面让我们来详细解释这个问题以及可能的解决方法。 ### 问题原因分析1. **相对路径问题…

mysql8.0找不到my.ini

报错问题解释&#xff1a; MySQL 8.0 在Windows系统中通常不需要 my.ini 文件&#xff0c;因为安装程序会在 %PROGRAMDATA%\MySQL\MySQL Server 8.0\ &#xff08;通常是 C:\ProgramData\MySQL\MySQL Server 8.0\&#xff09;创建默认的配置文件。如果你的系统中找不到 my.ini…

Harmony设计模式-单例模式

Harmony设计模式-单例模式 前言 软件设计模式&#xff08;[Design pattern](https://baike.baidu.com/item/Design pattern/10186718?fromModulelemma_inlink)&#xff09;&#xff0c;又称设计模式&#xff0c;是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经…

中文分词词云图

目录 一、分词1、分词方式方法2、分词优缺点 二、jieba使用示例1、引入库2、切分模式3、加载自定义字典 三、词的可视化1、读取数据2、数据处理3、统计词频4、去除停用词5、词云图1、pyecharts绘图2、WordCloud绘图 一、分词 1、分词方式方法 以构词规则为出发点的规则分词 全…

科普文章:怎么远程监控电脑屏幕?三种监控电脑屏幕的方法

远程监控公司电脑屏幕是一项重要的管理手段&#xff0c;它不仅有助于提升工作效率&#xff0c;还能确保公司信息安全和合规性。随着远程办公的普及&#xff0c;这一需求变得日益重要。下面我将详细介绍几种实现远程监控公司电脑屏幕的方法&#xff0c;以及实施过程中需要注意的…

看完再买不后悔!希喂、小米、霍尼韦尔宠物空气净化器性价比比拼

在忙碌的工作之余&#xff0c;养一只猫真的能治愈一切的不快&#xff0c;让我们的心灵得到片刻的宁静。然而&#xff0c;这份宁静背后&#xff0c;却隐藏着一些不易察觉的烦恼——猫浮毛和异味。 猫浮毛&#xff0c;这个看似微不足道的小问题&#xff0c;实则给许多宠物主人带…

我在高职教STM32——LCD液晶显示(2)

大家好&#xff0c;我是老耿&#xff0c;高职青椒一枚&#xff0c;一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次&#xff0c;同行应该都懂的&#xff0c;老师在课堂上教学几乎是没什么成就感的。正因如此&#xff0c;才有了借助 CSDN 平台寻求认同感和成就…

LabVIEW_TDMS

1.TDMS设置属性 想给这里写属性怎么整 使用TDMS设置属性函数时&#xff0c;对组名称与通道名称不设置&#xff0c;即可达到上图中的样式。 PS&#xff1a;属性名称如果设置一样则最终生效的值为最后写入的值。如将属性2修改为属性1&#xff0c;则最终只有1个属性1&#xff0c…