Flutter实战一Flutter聊天应用(十二)

119 篇文章 9 订阅
82 篇文章 1416 订阅

由于当前项目的账号是直接使用Google账户,iOS系统问题不大,但是Android系统如果没有Google框架,则无法使用我们的应用程序。因此,我们需要创建自己的账户数据。在这篇文章中,我们会创建一个登陆屏幕和注册屏幕,两个屏幕的UI如下图所示:

这里写图片描述

关于UI布局的内容不是这篇文章的重点,所以不会具体描述,只会展示代码并陈述布局思路。有关UI布局的内容可以查看《Flutter进阶—构建布局实例》《Flutter进阶—布局方法演示》《Flutter进阶—布局一个控件》《Flutter进阶—垂直和水平布局》等文章。

实现登陆屏幕

首先添加三个图像资源,分别为登陆屏幕的背景、注册屏幕的背景和应用程序的Logo,具体的添加方法可以查看《Flutter基础—常用控件之图片》

这里写图片描述

我们在项目的lib目录下创建一个sign_in.dart文件,并添加下面的代码。

import 'package:flutter/material.dart';

class SignIn extends StatefulWidget {
  @override
  State createState() => new SignInState();
}

class SignInState extends State<SignIn> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      new Opacity(
          opacity: 0.3,
          child: new Container(
            decoration: new BoxDecoration(
              image: new DecorationImage(
                image: new ExactAssetImage('images/sign_in_background.jpg'),
                fit: BoxFit.cover,
              ),
            ),
          )),
      new Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
        ],
      )
    ]));
  }
}

为了实现透明背景,我们使用Stack控件,它可以一层一层地放置控件。Stack控件的第一层是Opacity控件,它可以控件其子控件的透明度,我们用Container控件包装指定的背景图片作为其子控件,并把透明度设置为0.3。第二层是Column控件,它能让多个子控件排成一列。mainAxisAlignment属性设置成MainAxisAlignment.spaceEvenly以使子控件们均匀的占用空间,crossAxisAlignment属性设置成CrossAxisAlignment.start以使子控件们靠左排列。现在我们开始往Column控件中添加子控件。

class SignInState extends State<SignIn> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
        //...
        children: <Widget>[
          new Center(
              child: new Image.asset(
            'images/talk_casually.png',
            width: MediaQuery.of(context).size.width * 0.4,
          )),
        ],
      )
    ]));
  }
}

这里写图片描述

第一个子控件是Image控件,由于其父控件设置成靠左排列,因此将其包装到Center控件中,以使Image控件居中显示。同时将Image控件的width属性设置为当前屏幕宽度的40%,使图像以合适的大小显示。

class SignInState extends State<SignIn> {
  final TextEditingController _usernameController = new TextEditingController();
  final TextEditingController _passwordController = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
        //...
        children: <Widget>[
          //...
          new Container(
              width: MediaQuery.of(context).size.width * 0.96,
              child: new Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    new TextField(
                      controller: _usernameController,
                      decoration: new InputDecoration(
                        hintText: 'Username',
                        icon: new Icon(
                          Icons.account_circle,
                        ),
                      ),
                    ),
                    new TextField(
                      controller: _passwordController,
                      obscureText: true,
                      keyboardType: TextInputType.number,
                      decoration: new InputDecoration(
                        hintText: 'Password',
                        icon: new Icon(
                          Icons.lock_outline,
                        ),
                      ),
                    ),
                  ])),
        ],
      )
    ]));
  }
}

第二个控件是Column控件,其包括两个TextField子控件,用于输入用户名与登陆密码。把Column控件包装在Container控件中,并且将其width属性设置成当前屏幕宽度的96%,是因为如果不这样做,效果如下所示:

这里写图片描述

上图中,输入框的输入区域一直到屏幕的边缘,反之,如果设置成96%的宽度,效果如下所示:

这里写图片描述

为了使屏幕整体效果更和谐,这里使输入框的输入区域与屏幕边缘保持一定距离。当然,具体使用怎样的效果还是看个人的审美吧!

class SignInState extends State<SignIn> {
  //...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
        //...
        children: <Widget>[
          //...
          new FlatButton(
            child: new Container(
              decoration: new BoxDecoration(
                color: Theme.of(context).accentColor,
              ),
              child: new Center(
                  child: new Text("Sign In",
                      style: new TextStyle(
                        color: const Color(0xff000000),
                      ))),
            ),
            onPressed: () {
              print('Sign In');
            },
          ),
        ],
      )
    ]));
  }
}

这里写图片描述

第三个子控件是FlatButton控件,它是一个平面按钮,后面我们会在这里添加登陆的代码。

class SignInState extends State<SignIn> {
  //...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
        //...
        children: <Widget>[
          //...
          new Center(
              child: new FlatButton(
            child: new Text("Don't have an account ?  Sign Up",
                style: new TextStyle(
                  color: const Color(0xff000000),
                )),
            onPressed: null,
          ))
        ],
      )
    ]));
  }
}

这里写图片描述

第四个子控件也是FlatButton控件,不过为了居中显示,将其包装在Center控件中。这个按钮用于导航到后面的注册屏幕。

显示登陆屏幕

我们在项目的lib目录下创建一个chat_screen.dart文件,然后我们将之前聊天屏幕的代码转移到新建的chat_screen.dart文件中,使main.dart文件显示以下代码:

import 'package:flutter/material.dart';
import 'sign_in.dart';

void main() {
  runApp(new TalkcasuallyApp());
}

class TalkcasuallyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: '谈天说地',
      home: new SignIn()
    );
  }
}

重新运行应用程序,就能显示我们的登陆屏幕。

这里写图片描述

实现注册屏幕

我们在项目的lib目录下创建一个sign_up.dart文件,并添加下面的代码。

import 'package:flutter/material.dart';

class SignUp extends StatefulWidget {
  @override
  State createState() => new SignUpState();
}

class SignUpState extends State<SignUp> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      new Opacity(
          opacity: 0.3,
          child: new Container(
            decoration: new BoxDecoration(
              image: new DecorationImage(
                image: new ExactAssetImage('images/sign_up_background.jpg'),
                fit: BoxFit.cover,
              ),
            ),
          )),
      new Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
          ])
    ]));
  }
}

上面的代码与登陆屏幕相似,所以我们直接往Column控件中添加子控件。

class SignUpState extends State<SignUp> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
          //...
          children: <Widget>[
            new BackButton(),
            new Text("  Sign Up",
                textScaleFactor: 2.0,
                style: new TextStyle(
                  color: const Color(0xff000000),
                )),
          ])
    ]));
  }
}

这里写图片描述

第一个子控件是BackButton控件,它会显示当前平台的返回按钮,点击返回到上一个屏幕。第二个子控件是Text控件,将textScaleFactor属性设置成2.0,使字体放大一倍显示。

class SignUpState extends State<SignUp> {
  final TextEditingController _usernameController = new TextEditingController();
  final TextEditingController _passwordController = new TextEditingController();
  final TextEditingController _emailController = new TextEditingController();
  final TextEditingController _phoneController = new TextEditingController();

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
          //...
          children: <Widget>[
            //...
            new Container(
                width: MediaQuery.of(context).size.width * 0.96,
                child: new Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      new TextField(
                        controller: _usernameController,
                        decoration: new InputDecoration(
                          hintText: 'Username',
                          icon: new Icon(
                            Icons.account_circle,
                          ),
                        ),
                      ),
                      new TextField(
                        controller: _passwordController,
                        obscureText: true,
                        keyboardType: TextInputType.number,
                        decoration: new InputDecoration(
                          hintText: 'Password',
                          icon: new Icon(
                            Icons.lock_outline,
                          ),
                        ),
                      ),
                      new TextField(
                        controller: _emailController,
                        decoration: new InputDecoration(
                          hintText: 'E-mail',
                          icon: new Icon(
                            Icons.email,
                          ),
                        ),
                      ),
                      new TextField(
                        controller: _phoneController,
                        decoration: new InputDecoration(
                          hintText: 'Phone',
                          icon: new Icon(
                            Icons.phone,
                          ),
                        ),
                      ),
                    ])),
    ]));
  }
}

这里写图片描述

第三个控件是Column控件,与登陆屏幕相似。

class SignUpState extends State<SignUp> {
  //...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
          //...
          children: <Widget>[
            //...
            new FlatButton(
              child: new Container(
                width: MediaQuery.of(context).size.width,
                decoration: new BoxDecoration(
                  color: Theme.of(context).accentColor,
                ),
                child: new Center(
                    child: new Text("Join",
                        style: new TextStyle(
                          color: const Color(0xff000000),
                        ))),
              ),
              onPressed: () {
                print('Sign In');
              },
            ),
          ])
    ]));
  }
}

这里写图片描述

第四个子控件是FlatButton控件,与登陆屏幕相似,后面会实现用户注册的代码。

class SignUpState extends State<SignUp> {
  //...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
          //...
          children: <Widget>[
            //...
            new Center(
                child: new FlatButton(
              child: new Text("Already have an account ?  Sign In",
                  style: new TextStyle(
                    color: const Color(0xff000000),
                  )),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ))
          ])
    ]));
  }
}

这里写图片描述

第五个子控件是包装在Center控件里的FlatButton控件,点击这个按钮可以返回上一个屏幕。

从登陆屏幕导航到注册屏幕

我们在sign_in.dart文件中添加一个_openSignUp方法,代码如下所示:

class SignInState extends State<SignIn> {
  //...
  void _openSignUp() {
    setState(() {
      Navigator.of(context).push(new MaterialPageRoute<Null>(
        builder: (BuildContext context) {
          return new SignUp();
        },
      ));
    });
  }
  //...
}

然后我们将_openSignUp方法添加到Column控件的第四个子控件中,代码如下所示:

import 'package:flutter/material.dart';
import 'sign_up.dart';
//...
class SignInState extends State<SignIn> {
  //...
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Stack(children: <Widget>[
      //...
      new Column(
        //...
        children: <Widget>[
          //...
          new Center(
              child: new FlatButton(
            child: new Text("Don't have an account ?  Sign Up",
                style: new TextStyle(
                  color: const Color(0xff000000),
                )),
            onPressed: _openSignUp,
          ))
        ],
      )
    ]));
  }
}

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

何小有

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

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

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

打赏作者

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

抵扣说明:

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

余额充值