Flutter Web(一)新建项目和登录页

flutter开发环境搭建略
如果是新搭建好的环境,需要开启web支持和windows支持
flutter config --enable-windows-desktop
flutter config --enable-web
创建项目名为spore,英文翻译为孢子,希望可以”做大做强“(无名之辈的发音)吧,毕竟谁不好大喜功呢!
flutter create spore
cd spore

web运行查看
flutter run -d Chrome
在这里插入图片描述

windows运行查看
flutter run -d Windows
在这里插入图片描述

本篇的主要目的就是把这个页面搞成登录页,就算OK
来说一下目录结构
在这里插入图片描述

红色箭头指向的两个文件夹是添加平台支持后才会有的,如果你的目录中没有,就是添加支持出问题,或者干脆忘记添加了。
蓝色箭头指向的是和本篇关系很大的两个文件,尤其是main.dart,是整个项目的主入口文件,灰常重要

因为是第一篇,就搞的尽量简单点,后面丰富吧,我一向提倡先解决有的问题,再解决好看的问题。当然也不能太不想个样子,lib下新建文件夹pages,pages新建login.dart

先贴代码的基本结构,注释说明

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {//继承StatefulWidget类,表示它是一个有状态的组件
  const LoginPage({Key? key}) : super(key: key);
  @override
  _LoginPageState createState() => _LoginPageState();//如果集成StatelessWidget类,这里就该是Widget build(BuildContext context)
}

class _LoginPageState extends State<LoginPage>{
  
  @override
  Widget build(BuildContext context) {//构建UI,写控件的地方
    // TODO: implement build
    throw UnimplementedError();
  }

}

flutter把控件从状态的角度分为两大类:StatefulWidget和StatelessWidget,据说懂RN的这个自然懂,反正我不懂。。。
StatefulWidget为了更好的提升实现状态管理和UI重绘等性能,设计成createState()返回一个组件的State对象来进行操作。具体原理先不用懂,反正就是王八的屁股—规定

基础勉强实现功能版
在这里插入图片描述
代码如下

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {//继承StatefulWidget类,表示它是一个有状态的组件
  const LoginPage({Key? key}) : super(key: key);
  @override
  _LoginPageState createState() => _LoginPageState();//如果集成StatelessWidget类,这里就该是Widget build(BuildContext context)
}

class _LoginPageState extends State<LoginPage>{
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();
  String? userName;
  String? password;

  @override
  Widget build(BuildContext context) {//构建UI,写控件的地方
    return Theme(
      data: ThemeData(),
      child: Scaffold(
        body: _buildPageContent(),
      ),
    );
  }

  Widget _buildPageContent() {
    return Container(
      color: const Color.fromARGB(255, 148, 200, 207),
      child: ListView(
        children: <Widget>[
          const Center(
            child: Text(
              "欢迎使用本系统",
              style: TextStyle(
                fontSize: 18, 
                color: Colors.black
              ),
              textScaleFactor: 3.2 //缩放倍数,没有这个字会很小
            )
          ),
          const SizedBox(height: 20.0),
          _buildLoginForm(),//缩进写到烦人,搞个方法。
          const SizedBox(height: 20.0),
        ],
      ),
    );
  }
  Container _buildLoginForm() {
    return Container(
      color: const Color.fromARGB(255, 45, 183, 201),
      child: Stack(//自由位置的组件
        children: [
          Center(
            child: Container(
              width: 500,
              height: 260,
              margin: EdgeInsets.only(top: 40),
              padding: EdgeInsets.all(10.0),
              decoration: BoxDecoration(//白色的圆角方框
                borderRadius: BorderRadius.all(Radius.circular(40.0)),
                color: Colors.white,
              ),
              child: Form(
                key: formKey,
                child: Column(
                  children: [
                    Container(
                      child: TextFormField(
                        initialValue: "admin",//可以不要这个参数
                        onSaved: (v) {
                          userName = v;
                        },
                        validator: (v) {
                          return v!.isEmpty ? "请输入用户名" : null;
                        },
                      ),
                    ),
                    Container(
                      child: TextFormField(
                        initialValue: "123456",
                        obscureText: true,
                        onSaved: (v) {
                          password = v;
                        },
                        validator: (v) {
                          return v!.isEmpty ? "请输入密码" : null;
                        },
                      ),
                    ),
                  ],
                )
              )
            ),
          ),
          Container(
            height: 260,
            alignment: Alignment.bottomCenter,
            child: SizedBox(
              width: 420,
              child: ElevatedButton(
                onPressed: _login,
                style: ButtonStyle(
                  shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(40.0))),
                ),
                child: const Text("登录", style: TextStyle(color: Colors.white70, fontSize: 20)),
              ),
            ),
          ),
        ],
      ),
    );
  }
  _login(){
    var form = formKey.currentState!;
    if (!form.validate()) {
      return;
    }
    form.save();//会调用TextFormField的onSave

    if(userName=='admin' && password=='123456'){
      _showAlertDialog(context,'登录成功');
    }else{
      _showAlertDialog(context,'用户名或密码错误');
    }
  }

  //没有找到方便的toast控件,搞个这代替
  _showAlertDialog(BuildContext context,String msg) {
  
    //设置按钮
    Widget okButton = TextButton(
      child: const Text("OK"),
      onPressed: () {Navigator.of(context).pop(); },
    );
  
    //设置对话框
    AlertDialog alert = AlertDialog(
      title: const Text("提示"),
      content: Text(msg),
      actions: [
        okButton,
      ],
    );
  
    //显示对话框
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }
}

精细化版,抄别人的,最后贴地址
在这里插入图片描述
虽然还是丑,以后有的是机会再优化,代码如下:

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {//继承StatefulWidget类,表示它是一个有状态的组件
  const LoginPage({Key? key}) : super(key: key);
  @override
  _LoginPageState createState() => _LoginPageState();//如果集成StatelessWidget类,这里就该是Widget build(BuildContext context)
}

class _LoginPageState extends State<LoginPage>{
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();
  String? userName;
  String? password;
  FocusNode focusNodeUserName = FocusNode();
  FocusNode focusNodePassword = FocusNode();

  @override
  Widget build(BuildContext context) {//构建UI,写控件的地方
    return Theme(
      data: ThemeData(),
      child: Scaffold(
        body: _buildPageContent(),
      ),
    );
  }

  Widget _buildPageContent() {
    return Container(
      color: const Color.fromARGB(255, 110, 238, 255),
      child: ListView(
        children: <Widget>[
          const Center(
            child: Text(
              "欢迎使用本系统",
              style: TextStyle(
                fontSize: 18, 
                color: Colors.black
              ),
              textScaleFactor: 3.2 //缩放倍数,没有这个字会很小
            )
          ),
          const SizedBox(height: 20.0),
          _buildLoginForm(),//缩进写到烦人,搞个方法。
          const SizedBox(height: 20.0),
        ],
      ),
    );
  }
  Container _buildLoginForm() {
    return Container(
      padding: const EdgeInsets.fromLTRB(0, 30, 0, 30),
      color: const Color.fromARGB(255, 45, 183, 201),
      child: Stack(//自由位置的组件
        children: [
          Center(
            child: Container(
              width: 500,
              height: 320,
              margin: const EdgeInsets.only(top: 40),
              padding: const EdgeInsets.all(10.0),
              decoration: const BoxDecoration(//白色的圆角方框
                borderRadius: BorderRadius.all(Radius.circular(40.0)),
                color: Colors.white,
              ),
              child: Form(
                key: formKey,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,//垂直居中
                  children: [
                    Container(
                      padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
                      child: TextFormField(
                        focusNode: focusNodeUserName,
                        initialValue: "admin",
                        style: const TextStyle(color: Colors.black),
                        decoration: const InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: "用户名",
                          icon: Icon(
                            Icons.people,
                            color: Colors.blue,
                          ),
                        ),
                        onSaved: (v) {
                          userName = v;
                        },
                        validator: (v) {
                          return v!.isEmpty ? "请输入用户名" : null;
                        },
                        onFieldSubmitted: (v) {//按shift触发方法
                          focusNodePassword.requestFocus();
                        },
                      ),
                    ),
                    Container(
                      padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
                      child: TextFormField(
                        focusNode: focusNodePassword,
                        initialValue: "123456",
                        obscureText: true,
                        style: const TextStyle(color: Colors.black),
                        decoration: const InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: "密码",
                          icon: Icon(
                            Icons.lock,
                            color: Colors.blue,
                          ),
                        ),
                        onSaved: (v) {
                          password = v;
                        },
                        validator: (v) {
                          return v!.isEmpty ? "请输入密码" : null;
                        },
                        onFieldSubmitted: (v) {
                          _login();
                        },
                      ),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: <Widget>[
                        TextButton(
                          child: const Text(
                            '去注册',
                            style: TextStyle(color: Colors.blue),
                          ),
                          onPressed: () {},
                        ),
                        TextButton(
                          child: const Text(
                            '忘记密码',
                            style: TextStyle(color: Colors.black45),
                          ),
                          onPressed: () {},
                        )
                      ],
                    ),
                  ],
                )
              )
            ),
          ),
          Container(
            height: 320,
            alignment: Alignment.bottomCenter,
            child: SizedBox(
              width: 420,
              child: ElevatedButton(
                onPressed: _login,
                style: ButtonStyle(
                  shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: BorderRadius.circular(40.0))),
                ),
                child: const Text("登录", style: TextStyle(color: Colors.white70, fontSize: 20)),
              ),
            ),
          ),
        ],
      ),
    );
  }
  _login(){
    var form = formKey.currentState!;
    if (!form.validate()) {
      return;
    }
    form.save();//会调用TextFormField的onSave

    //等集成dio再优化
    if(userName=='admin' && password=='123456'){
      _showAlertDialog(context,'登录成功');
    }else{
      _showAlertDialog(context,'用户名或密码错误');
    }
  }

  //没有找到方便的toast控件,搞个这代替
  _showAlertDialog(BuildContext context,String msg) {
  
    //设置按钮
    Widget okButton = TextButton(
      child: const Text("OK"),
      onPressed: () {Navigator.of(context).pop(); },
    );
  
    //设置对话框
    AlertDialog alert = AlertDialog(
      title: const Text("提示"),
      content: Text(msg),
      actions: [
        okButton,
      ],
    );
  
    //显示对话框
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return alert;
      },
    );
  }
}

注册页面和登录差不多,举一反三尝试复制一份改个名字,稍作调整,就可以了

我并不是精通flutter的移动开发之后写这个博客,是拿别人的项目一边抄,一边学习,一边摸索,一边实践,顺便记录下来,我直接参考的项目地址就列出来,如果有和我想法差不多的,我建议直接拿去学习研究吧

github地址:flutterAdmin gitee也有,但是作者好久没更新了,我就不贴了

另一个 知乎看到的另一个看着也不错的,可以看看,作参考

本篇博客完整demo下载spore-01.zip

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

公贵买其鹿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值