【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

简介: 【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

章节内容【02】

写一个注册页面以及配置打包选项打包安卓apk测试

开发背景

上次我们安装了flutter 配置了vs-code的环境,这次我们来写一个注册页面,以及最基本的打包。

闲话不多,开源仓库地址,可以观摩已经写好的代码:

https://gitee.com/youyacao/ff-flutter

实战开始

首先我们新建一个flutter 项目,记得选择是空内容,那么默认flutter项目里面是hello word代码,main.dart便是我们的主页代码。

我们查看设计图,

先看登录页面,有手机号填写表单,有密码表单,有注册按钮,登录按钮,以及忘记密码文字。

我们先把样式写出来,如下:

import 'package:flutter/material.dart';
void main() {
  runApp(const MainApp());
}
class MainApp extends StatelessWidget {
  const MainApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Free Friend'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextField(
                decoration: InputDecoration(
                  labelText: '请输入手机号',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.phone,
              ),
              const SizedBox(height: 16.0),
              TextField(
                decoration: InputDecoration(
                  labelText: '请输入密码',
                  border: OutlineInputBorder(),
                ),
                obscureText: true,
              ),
              const SizedBox(height: 24.0),
              ElevatedButton(
                onPressed: () {
                  // 注册按钮点击事件
                  print('注册按钮被点击');
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red, // 设置红色背景
                ),
                child: const Text('注册'),
              ),
              const SizedBox(height: 8.0),
              ElevatedButton(
                onPressed: () {
                  // 登录按钮点击事件
                  print('登录按钮被点击');
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red, // 设置红色背景
                ),
                child: const Text('登录'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

运行查看,我们看到结果样子,

对比设计图有几个点要改,1,顶部文字应该大写并且居中,而且字体是PingFang SC 2,手机号表单上上面要加一行描述, 3,输入密码下方需要增加一个同意协议的选项框。

在pubspec.yaml 中加入 字体

fonts:
    - family: PingFang SC
      fonts:
        - asset: fonts/PingFangSC-Regular.ttf

修改源代码:

import 'package:flutter/material.dart';
void main() {
  runApp(const MainApp());
}
class MainApp extends StatelessWidget {
  const MainApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text(
            'Free Friend',
            style: TextStyle(
              fontSize: 24.0, // 设置字体大小
              fontFamily: 'PingFang SC', // 设置字体为 PingFang SC
            ),
          ),
          centerTitle: true, // 居中标题
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextField(
                decoration: InputDecoration(
                  labelText: '请输入手机号',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.phone,
              ),
              const SizedBox(height: 16.0),
              TextField(
                decoration: InputDecoration(
                  labelText: '请输入密码',
                  border: OutlineInputBorder(),
                ),
                obscureText: true,
              ),
              const SizedBox(height: 24.0),
              ElevatedButton(
                onPressed: () {
                  // 注册按钮点击事件
                  print('注册按钮被点击');
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red, // 设置红色背景
                ),
                child: const Text('注册'),
              ),
              const SizedBox(height: 8.0),
              ElevatedButton(
                onPressed: () {
                  // 登录按钮点击事件
                  print('登录按钮被点击');
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red, // 设置红色背景
                ),
                child: const Text('登录'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

并且我们在根目录创建资源文件夹目录

assets:
    - assets/
    - assets/images/
    - assets/icons/
    - assets/fonts/

代码对应写,文件夹也对应创立。

对应下载字体放在目录下,

右下角报错 Could not start extension, shellsheck not installed properly!Error: Command failed: shellcheck —version ‘shellcheck’

这是 shellcheck没有正确安装,

安装即可,再次运行

这时候我们开始做另外两个地方,

另外这里先扩展知识下:

一个标准的flutter项目目录

your_project/
├── android/               # Android 平台的相关文件
├── assets/                # 静态资源,如图片、音频等
├── build/                 # 编译生成的文件
├── ios/                   # iOS 平台的相关文件
├── lib/                   # Dart 源代码
│   ├── main.dart          # 应用程序的入口文件
│   └── ...                # 其他 Dart 文件和目录
├── test/                  # 单元测试文件
├── web/                   # Web 平台相关文件
├── windows/               # Windows 平台相关文件
├── macos/                 # MacOS 平台相关文件
├── linux/                 # Linux 平台相关文件
├── .gitignore             # Git 忽略文件配置
├── .metadata              # 项目信息文件
├── analysis_options.yaml  # 分析和代码检查规则
├── pubspec.yaml           # 项目配置文件,包含依赖项和其他配置信息
└── README.md              # 项目说明文件

其2,一个标准的社交软件的lib源代码dart文件目录大概是这样,

lib/
├── main.dart                # 应用程序入口文件
├── app/
│   ├── app.dart             # 应用程序的全局设置和配置
│   └── routes.dart          # 应用程序的路由配置
├── models/
│   ├── user.dart            # 用户数据模型
│   ├── post.dart            # 帖子数据模型
│   └── message.dart         # 消息数据模型
├── services/
│   ├── api_service.dart     # API 服务类
│   ├── auth_service.dart    # 身份验证服务
│   └── database_service.dart# 数据库服务
├── views/
│   ├── home/
│   │   ├── home_view.dart   # 主页视图
│   │   ├── home_viewmodel.dart # 主页视图模型
│   ├── profile/
│   │   ├── profile_view.dart # 个人资料视图
│   │   ├── profile_viewmodel.dart # 个人资料视图模型
│   ├── chat/
│   │   ├── chat_view.dart    # 聊天视图
│   │   ├── chat_viewmodel.dart # 聊天视图模型
│   ├── login/
│   │   ├── login_view.dart   # 登录视图
│   │   ├── login_viewmodel.dart # 登录视图模型
├── widgets/
│   ├── custom_button.dart    # 自定义按钮组件
│   ├── custom_textfield.dart # 自定义文本框组件
│   └── ...                   # 其他自定义组件
├── utils/
│   ├── constants.dart        # 常量定义
│   ├── utils.dart            # 工具函数
│   └── validators.dart       # 验证函数
└── resources/
    ├── colors.dart           # 颜色资源
    ├── strings.dart          # 字符串资源
    └── themes.dart           # 主题资源

目录结构说明

  • main.dart:应用程序的入口文件。
  • app/:存放全局设置和路由配置。
  • models/:数据模型文件夹,定义用户、帖子、消息等数据结构。
  • services/:服务文件夹,包括 API 服务、身份验证服务、数据库服务等。
  • views/:视图文件夹,按照功能模块组织,例如主页、个人资料、聊天、登录等。
  • widgets/:自定义组件文件夹,存放常用的自定义 UI 组件。
  • utils/:工具文件夹,包含常量定义、工具函数和验证函数等。
  • resources/:资源文件夹,包括颜色、字符串和主题资源等。

目前我们还没有开始分类这些目录,而是用的main.dart应用程序主入口来写,本篇只是给看测试,另附上蜻蜓z雪花版的文件目录参考:

完整的项目目录是:

├─configs
├─controllers
│  ├─base
│  ├─movie
│  └─public
├─db
├─mixins
│  ├─movie
│  └─public
├─models
│  ├─base
│  ├─movie
│  ├─public
│  ├─review
│  └─user
├─pages
│  ├─advertising
│  │  └─advertising_home
│  │      ├─controllers
│  │      ├─models
│  │      └─widgets
│  ├─barrage
│  │  ├─send
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  └─site
│  │      └─widgets
│  ├─brush
│  │  ├─drama
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─enter
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─full
│  │  │  ├─controllers
│  │  │  ├─mixins
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─home
│  │  │  ├─controllers
│  │  │  ├─mixins
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─reply
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─review
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  └─synopsis
│  │      ├─controllers
│  │      └─widgets
│  ├─home
│  │  ├─feedback
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─home_page
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─pop_up_ad
│  │  │  └─widgets
│  │  ├─prompt
│  │  │  └─widgets
│  │  └─sort_page
│  │      ├─controllers
│  │      ├─models
│  │      └─widgets
│  ├─mine
│  │  ├─clear_cache
│  │  │  └─widgets
│  │  ├─clear_record
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─gold_rule
│  │  │  └─widgets
│  │  ├─invite
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─invite_history
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─mine_home
│  │  │  └─widgets
│  │  ├─mysubs
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─my_download
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─my_favorite
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─my_statistics
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─user_info
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  └─withdraw
│  │      ├─controllers
│  │      └─widgets
│  ├─movie
│  │  ├─actor
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─cache_play
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─detail
│  │  │  ├─controllers
│  │  │  ├─mixins
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─download
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─drama
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─exception
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─full_drama
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─line
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─play
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  │      └─player
│  │  ├─play_full
│  │  │  ├─controllers
│  │  │  ├─mixins
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─record
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─score
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─share
│  │  │  └─widgets
│  │  └─synopsis
│  │      ├─controllers
│  │      └─widgets
│  ├─public
│  │  ├─splash_screen
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─tabbar
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  └─upgrade
│  │      ├─controllers
│  │      └─widgets
│  ├─review
│  │  ├─enter
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─home
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─record
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  └─reply
│  │      ├─controllers
│  │      ├─models
│  │      └─widgets
│  ├─site
│  │  ├─password
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─phone
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  ├─question
│  │  │  ├─controllers
│  │  │  └─widgets
│  │  └─site_home
│  │      ├─controllers
│  │      └─widgets
│  ├─sort
│  │  ├─search
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  ├─sort_home
│  │  │  ├─controllers
│  │  │  ├─models
│  │  │  └─widgets
│  │  └─suggested
│  │      ├─controllers
│  │      └─widgets
│  └─user
│      ├─choose
│      │  └─widgets
│      ├─login
│      │  ├─controllers
│      │  ├─models
│      │  └─widgets
│      ├─pact
│      │  ├─controllers
│      │  ├─models
│      │  └─widgets
│      ├─phone_recover
│      │  ├─controllers
│      │  └─widgets
│      ├─register
│      │  ├─controllers
│      │  ├─models
│      │  └─widgets
│      └─safety_recover
│          ├─controllers
│          └─widgets
├─routes
│  ├─middlewares
│  └─modules
├─themes
│  └─pkg
├─utils
└─widgets
    ├─base
    │  └─app_network_image
    ├─emoji_text_field
    │  └─widgets
    ├─public
    │  └─page_indicator
    │      └─widgets
    ├─skeleton
    ├─ui
    │  ├─ad
    │  ├─barrage
    │  ├─cover
    │  └─review
    └─video_player
        ├─types
        └─widgets
            └─panel

这是优雅草蜻蜓z雪花版项目的客户端目录,为什么要先发出来呢,因为我们本次开发社交软件也是要对接好蜻蜓z系统的后端的,在第一篇中已经发过接口文档地址了,大家可以去参考看看。

接着我们把剩下两个问题改了好开始下一篇大整理了,

在输入手机号表单前面加上这个提示字样,字体也是pingfang SC,在请输入手机号表单上面增加描述文字“Please login your account”,文字描述FontWeight.w800,文字颜色为白色,这里我们需要用在 Column 中添加一个新的 Text 小部件,设置 Text 小部件的样式。

const Text(
  "Please login your account",
  style: TextStyle(
    color: Colors.white,
    fontSize: 32,
    fontFamily: "PingFang SC",
    fontWeight: FontWeight.w800,
  ),
),

大概是这样,我们加入在前面,

优雅草央千澈发现文字是加上了我们是不是还缺个背景色,我们只需要在 设置 Scaffold 的 backgroundColor 加入

backgroundColor: const Color(0xFF1E1E1E), // 设置背景色为 #1E1E1E

Scaffold扩展知识

在 Flutter 中,Scaffold 是一个非常重要的容器组件,它为应用程序提供了一个基本的结构和布局。这相当于一个框架,方便你在应用中创建常见的 UI 元素和布局,如应用栏、抽屉、底部导航栏等。

Scaffold 组件的关键属性

  • appBar: 一个位于顶部的应用栏(AppBar),通常包含标题、导航按钮和其他操作项。
  • body: 主体内容区域,用于放置应用的主要内容。
  • drawer: 一个抽屉(Drawer),从屏幕边缘滑出,用于显示导航链接或选项。
  • bottomNavigationBar: 一个位于底部的导航栏,用于在不同的页面之间切换。
  • floatingActionButton: 一个悬浮按钮,通常用于触发主要操作。
  • backgroundColor: 背景颜色。

这里注意在手机号前面还有国家地区选择,可以使用 DropdownButton 或 DropdownButtonFormField 来实现。这里我将使用 DropdownButtonFormField 来创建一个可选择国家地区号的下拉菜单。

// 示例国家地区号列表
    final List<String> countryCodes = ['+1', '+86', '+91', '+44', '+33'];
    // 默认选择的国家地区号
    String selectedCountryCode = countryCodes[0];
 Row(
                children: [
                  DropdownButtonFormField<String>(
                    value: selectedCountryCode,
                    onChanged: (String? newValue) {
                      if (newValue != null) {
                        selectedCountryCode = newValue;
                      }
                    },
                    items: countryCodes.map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(value),
                      );
                    }).toList(),
                    decoration: const InputDecoration(
                      labelText: '选择国家地区号',
                      border: OutlineInputBorder(),
                    ),
                  ),
                  const SizedBox(width: 8.0),
                  Expanded(
                    child: TextField(
                      decoration: const InputDecoration(
                        labelText: '请输入手机号',
                        border: OutlineInputBorder(),
                      ),
                      keyboardType: TextInputType.phone,
                    ),
                  ),
                ],
              ),

扩展知识

DropdownButton 和 DropdownButtonFormField 是两个常用的组件,用于创建下拉菜单和表单中的下拉选择项。它们的区别在于 DropdownButtonFormField 更加适合用于表单验证和处理。

区别与使用场景

DropdownButton:适用于独立使用的下拉菜单,不需要表单验证。

DropdownButtonFormField:适用于表单中的下拉菜单,需要表单验证和处理。

不过我们出现了“Use ‘const’ with the constructor to improve performance.
Try adding the ‘const’ keyword to the constructor invocation.”
这样的提示。

扩展知识

在 Flutter 和 Dart 中,const 和非 const(或 final 和普通变量)有着重要的区别,它们主要用于优化性能和管理不可变数据。

const:在编译时初始化,完全不可变,用于优化性能。

final:在运行时初始化,只能被赋值一次,用于定义在运行时确定但不可改变的值。

普通变量:可以在任何时候修改,适用于需要频繁更改的数据。

ok根据提示,我们需要完整的修改一下代码,

import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
void main() {
  // 初始化日志记录器
  Logger.root.level = Level.ALL;
  Logger.root.onRecord.listen((record) {
    debugPrint('${record.level.name}: ${record.time}: ${record.message}');
  });
  runApp(const MainApp());
}
class MainApp extends StatelessWidget {
  const MainApp({super.key});
  @override
  Widget build(BuildContext context) {
    final logger = Logger('MainApp');
    logger.info('Building MainApp');
    // 示例国家地区号列表
    final List<String> countryCodes = ['+1', '+86', '+91', '+44', '+33'];
    // 默认选择的国家地区号
    String selectedCountryCode = countryCodes[0];
    return MaterialApp(
      home: Scaffold(
        backgroundColor: const Color(0xFF1E1E1E), // 设置背景色为 #1E1E1E
        appBar: AppBar(
          title: const Text(
            'Free Friend',
            style: TextStyle(
              fontSize: 24.0, // 设置字体大小
              fontFamily: 'PingFang SC', // 设置字体为 PingFang SC
            ),
          ),
          centerTitle: true, // 居中标题
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                "Please login your account",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 32,
                  fontFamily: "PingFang SC",
                  fontWeight: FontWeight.w800,
                ),
              ),
              const SizedBox(height: 16.0),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,  // 使用 spaceBetween 对齐方式
                children: [
                  Flexible(
                    flex: 1,  // 给 DropdownButtonFormField 分配一部分空间
                    child: DropdownButtonFormField<String>(
                      value: selectedCountryCode,
                      onChanged: (String? newValue) {
                        if (newValue != null) {
                          selectedCountryCode = newValue;
                        }
                      },
                      items: countryCodes.map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value),
                        );
                      }).toList(),
                      decoration: const InputDecoration(
                        labelText: '选择国家地区号',
                        border: OutlineInputBorder(),
                      ),
                      style: const TextStyle(fontSize: 16),  // 设置字体大小
                    ),
                  ),
                  const SizedBox(width: 8.0),
                  Expanded(
                    flex: 2,  // 给 TextField 分配更多的空间
                    child: TextField(
                      decoration: const InputDecoration(
                        labelText: '请输入手机号',
                        border: OutlineInputBorder(),
                      ),
                      keyboardType: TextInputType.phone,
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 16.0),
              TextField(
                decoration: const InputDecoration(
                  labelText: '请输入密码',
                  border: OutlineInputBorder(),
                ),
                obscureText: true,
              ),
              const SizedBox(height: 24.0),
              ElevatedButton(
                onPressed: () {
                  // 注册按钮点击事件
                  logger.info('注册按钮被点击');
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red, // 设置红色背景
                ),
                child: const Text('注册'),
              ),
              const SizedBox(height: 8.0),
              ElevatedButton(
                onPressed: () {
                  // 登录按钮点击事件
                  logger.info('登录按钮被点击');
                },
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red, // 设置红色背景
                ),
                child: const Text('登录'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

其次我们看到在提示登录上方还有 free firend大字 样, 因此我们写:

const Text(
                "Free Friend",
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 61.87,
                  fontFamily: "PingFang SC",
                  fontWeight: FontWeight.w800,
                ),
              ),
              const SizedBox(height: 16.0),

在输入密码下方加入同意协议代码:

Row(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.start,
    crossAxisAlignment: CrossAxisAlignment.center,
    children:[
        Container(
            width: 38,
            height: 38,
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                border: Border.all(color: Colors.white, width: 2, ),
            ),
        ),
        SizedBox(width: 20),
        Text(
            "You agree to our Terms",
            style: TextStyle(
                color: Colors.white,
                fontSize: 32,
                fontFamily: "PingFang SC",
                fontWeight: FontWeight.w500,
            ),
        ),
    ],
)

这里代码中

children:[
        Container(
            width: 38,
            height: 38,
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10),
                border: Border.all(color: Colors.white, width: 2, ),
            ),
        ),

肯定是不对的,这里只是用来做个样子,这里我们应该用选框组件,

在 Flutter 中实现同意协议的勾选框(CheckBox)通常可以使用 Checkbox 组件。为了更好地用户体验,您可以将 Checkbox 和 Text 组件组合在一起,创建一个带有同意协议的行(Row)。

再对注册按钮进行调整:

我们对按钮加宽度,加背景色,这里需要知道扩展知识,
flutter 中对颜色表达 有4种方式,

  1. 使用颜色常量,2. 使用 ARGB 表示颜色,3. 使用十六进制表示颜色,4. 使用 Material 颜色
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter 颜色示例'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              height: 50,
              width: 50,
              color: Colors.red,
              child: Text('红色'),
            ),
            Container(
              height: 50,
              width: 50,
              color: Color.fromARGB(255, 0, 255, 0),
              child: Text('绿色'),
            ),
            Container(
              height: 50,
              width: 50,
              color: Color(0xFF0000FF),
              child: Text('蓝色'),
            ),
            Container(
              height: 50,
              width: 50,
              color: Colors.amber[600],
              child: Text('琥珀色'),
            ),
          ],
        ),
      ),
    );
  }
}

因此注册按钮的背景为

backgroundColor:Color(0xffe7568c), // 设置红色背景

对登录按钮进行调整,增加一个expanded组件,

Expanded 组件是 Flutter 中的一个布局组件,通常用于在行(Row)、列(Column)或弹性(Flex)布局中占据可用的剩余空间。这使得它在创建响应式布局时非常有用。

Expanded 组件的用途

填充剩余空间:在行或列布局中占据剩余的可用空间。

灵活调整:与其他布局组件(如 Flexible)结合使用,可以实现灵活的布局分配。

大家有没有发现 这个组件和margin是差不多的,所以编程一定是一门通门门通。

Expanded( // 添加 Expanded 组件
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: ElevatedButton(
                    onPressed: () {
                      // 登录按钮点击事件
                      logger.info('登录按钮被点击');
                    },
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Color(0xffe7568c), // 设置红色背景
                      fixedSize: Size(630, 48), // 设置按钮宽度为 630
                    ),
                    child: const Text('登录'),

现在还差把登录页面背景框改掉,

为了在登录按钮上方加入文字 “Already have an account?” 并保持布局在页面底部,可以在 Expanded 组件中添加一个 Column 来包含这两个组件。以下是修改后的代码:

Expanded(
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Text(
                        "Already have an account?",
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 32,
                          fontFamily: "PingFang SC",
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      const SizedBox(height: 8.0),
                      ElevatedButton(
                        onPressed: () {
                          // 登录按钮点击事件
                          logger.info('登录按钮被点击');
                        },
                        style: ElevatedButton.styleFrom(
                          backgroundColor: Color(0xffe7568c), // 设置红色背景
                          fixedSize: Size(630, 48), // 设置按钮宽度为 630
                        ),
                        child: const Text('登录'),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

最后我们需要将登录框的,背景改为透明色,边框颜色改为白色

style: ElevatedButton.styleFrom(
                          backgroundColor: Color(0xffe7568c), // 设置红色背景
                          fixedSize: Size(630, 48), // 设置按钮宽度为 630
                        ),

也就是这部分代码,这时候涉及两个知识点,我们需要把OutlinedButton 代替 ElevatedButton

OutlinedButton(
                        onPressed: () {
                          // 登录按钮点击事件
                          logger.info('登录按钮被点击');
                        },
                        style: OutlinedButton.styleFrom(
                          side: BorderSide(color: Colors.white, width: 2), // 设置边框颜色为白色
                          fixedSize: Size(630, 48), // 设置按钮宽度为 630
                          backgroundColor: Colors.transparent, // 去掉背景色
                        ),
                        child: Text(
                          '登录',
                          style: TextStyle(
                            color: Colors.white, // 设置文字颜色为白色
                            fontSize: 16.0, // 可以根据需要调整字体大小

扩展知识

在Flutter中,OutlinedButtonElevatedButton是两种不同风格的按钮组件,它们之间的主要区别体现在视觉表现和设计风格上。以下是对两者的详细比较:

OutlinedButton

  1. 视觉特点
  • 具有边框(outline),通常为黑色或灰色。
  • 背景是透明的,不会覆盖其下的内容。
  • 按下时只有边框颜色会发生变化,背景保持不变。
  1. 适用场景
  • 当需要突出按钮的轮廓而不是整体填充时使用。
  • 适合搭配浅色背景或者当希望按钮看起来更轻盈时。
  1. 样式定制
  • 可以通过style属性来自定义边框宽度、颜色等样式。

扩展知识Flutter中常见的Flutter按钮组件:

1. **ElevatedButton**

  • 特点:具有阴影效果,看起来像是浮起的。
  • 适用场景:适用于大多数需要突出显示的按钮。

2. **OutlinedButton**

  • 特点:有边框但没有填充色,看起来更简洁。
  • 适用场景:适合用于需要强调边界或与背景对比明显的场合。

3. **TextButton**

  • 特点:仅有文本,无任何背景或边框。
  • 适用场景:适用于文字为主且不需要额外视觉强调的按钮。

4. **IconButton**

  • 特点:专门用于显示图标,可以设置图标大小和颜色。
  • 适用场景:适合在界面中需要快速执行操作的图标按钮。

5. **MaterialButton**

  • 特点:类似于ElevatedButton,但提供了更多的样式选项。
  • 适用场景:适用于需要更多自定义样式的场景。

6. **RawMaterialButton**

  • 特点:提供了最基础的按钮实现,允许最大程度的自定义。
  • 适用场景:适用于需要高度定制按钮外观的情况。

7. **FloatingActionButton**

  • 特点:圆形按钮,通常带有图标,悬浮在屏幕边缘。
  • 适用场景:常用于导航或主要操作的快速执行。

8. **CupertinoButton**

  • 特点:符合iOS设计风格的按钮。
  • 适用场景:适用于需要在Flutter应用中融入iOS风格元素的情况。

9. **ToggleButton**

  • 特点:可以切换状态的按钮,通常用于开关功能。
  • 适用场景:适用于需要表示开/关状态的场景。

10. **CheckboxButton**

  • 特点:结合了复选框功能的按钮。
  • 适用场景:适用于需要用户选择多个选项的场景。

本页做为测试的首页基本就算完成了,接下来我们打包安卓APK,本文篇幅太多了-apk打包完整流程我们就留在第三篇幅吧

优雅草央千澈-只发干货!欢迎点赞关注+收藏!

目录
打赏
0
1
1
0
183
分享
相关文章
【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
103 75
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【06】flutter完成注册页面-密码登录-手机短信验证-找回密码相关页面-并且实现静态跳转打包demo做演示-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【Java若依框架】RuoYi-Vue的前端和后端配置步骤和启动步骤
本文介绍了如何配置和启动基于Java的若依(RuoYi)项目,涵盖后端和前端的详细步骤。首先,准备Redis、MySQL以及IDE(如Idea和VS)。接着,通过GitHub获取代码并导入到IDE中,执行必要的SQL文件和配置数据库密码。然后,启动Redis并进行相关配置。最后,按照前端配置步骤克隆前端代码库,打开终端执行命令完成前端配置。整个过程详细记录了每一步的操作,帮助开发者顺利部署若依项目。 如果你觉得有帮助,请点赞、关注和收藏,这将是我持续分享的动力!
95 1
|
11天前
|
圈子源码如何打包生成App小程序/开发一个圈子系统软件所需要的费用体现在哪里?
将PHP源码打包成App的过程涉及多个步骤和技术选择。以圈子源码为例,首先明确需求,确定App功能和目标用户群体,并根据需求开发小程序页面,如用户注册、圈子列表等。源码准备阶段确保源码适用于小程序开发,环境配置需安装IDE(如微信开发者工具)及依赖库。最后在IDE中打包小程序并上传至管理平台,通过审核后发布。费用方面,模板开发成本较低,定制开发则更高,具体取决于需求复杂度和第三方服务费用。
47 0
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。
接口测试工具攻略:轻松掌握测试技巧
在互联网快速发展的今天,软件系统的复杂性不断增加,接口测试工具成为确保系统稳定性的关键。它如同“翻译官”,模拟请求、解析响应、验证结果、测试性能并支持自动化测试,确保不同系统间信息传递的准确性和完整性。通过Apifox等工具,设计和执行测试用例更加便捷高效。接口测试是保障系统稳定运行的第一道防线。
API测试工具集合:让接口测试更简单高效
在当今软件开发领域,接口测试工具如Postman、Apifox、Swagger等成为确保API正确性、性能和可靠性的关键。Postman全球闻名但高级功能需付费,Apifox则集成了API文档、调试、Mock与自动化测试,简化工作流并提高团队协作效率,特别适合国内用户。Swagger自动生成文档,YApi开源但功能逐渐落后,Insomnia界面简洁却缺乏团队协作支持,Paw仅限Mac系统。综合来看,Apifox是国内用户的理想选择,提供中文界面和免费高效的功能。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等