笔记-Flutter应用启动闪屏到登陆界面

demo传送门git

闪屏

先看下闪屏动画的代码:github

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

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {

  AnimationController _controller;
  Animation _animation;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 3000));
    _animation = Tween(begin: 0.0, end: 1.0).animate(_controller);
    
    /* 动画事件监听器
    监听动画的执行状态,这里监听动画结束的状态,若是结束则执行页面跳转
     */
    _animation.addStatusListener((status){
      if (status == AnimationStatus.completed) {
        Navigator.of(context).pushAndRemoveUntil(
          MaterialPageRoute(builder: (context) => LoginView()),
        (route) => route==null
        );
      }
    });
    // 播放动画
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition( // 透明动画组件
      opacity: _animation, // 执行动画
      child: Image.network(
        'http://img.ph.126.net/L-kWzHFAymXFUvgauDtB-g==/2596888135149416738.jpg',
        scale: 2.0, // 缩放
        fit: BoxFit.cover,  // 充满容器
      ),
    );
  }
}

复制代码

AnimationContrllerAnimation的一个子类,能够用它来控制动画,好比执行时间。 设置好动画,就设置一个动画事件的监听器animation.addStatusListener,它能够监听到动画的执行状态,这里监听到动画结束,执行页面跳转动做。bash

关于图片的设置,以及路由的跳转,在后面都有详细的解释。网络

登陆界面

这是一个很简单的登陆界面,先看下页面里主要都有什么。闭包

  • 图片logo
  • 上下两个输入框
  • 一个登陆按钮

这边了解过Flutter的小伙伴们,看到了这个布局一会儿就可以想获得Column,下面看主体代码app

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

class LoginView extends StatefulWidget {
  @override
  _LoginViewState createState() => _LoginViewState();
}

class _LoginViewState extends State<LoginView> {

  var _photoController = TextEditingController();
  var _passController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(10.0),
              child: Image.asset('images/logo.jpg'),
            ),
            AccountTextField(),
            PasswordTextField(),
            LoginButton(),
          ],
        ),
      ),
    );
  }
  
  // 帐号TextField
  Widget AccountTextField() {
    return Padding(
        padding: const EdgeInsets.fromLTRB(15.0, 30.0, 15.0, 0.0),
        child: TextField(
          controller: _photoController,
          onChanged: (text) { // 内容变化
            print('输入了$text');
          },
          decoration: InputDecoration(
              prefixIcon: Icon(Icons.phone_iphone),
              fillColor: Colors.white70,
              filled: true,
              labelText: '请输入手机号'
          ),
        )
    );
  }
  
  // 密码TextField
  Widget PasswordTextField() {
    return Padding(
        padding: const EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 0.0),
        child: TextField(
          controller: _passController,
          decoration: InputDecoration(
              prefixIcon: Icon(Icons.email),
              fillColor: Colors.white70,
              filled: true,
              labelText: '请输入密码'
          ),
          obscureText: true,
        )
    );
  }
  
  // 登陆按钮
  Widget LoginButton() {
    return GestureDetector(
      child: Container(
        margin: const EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 0.0),
        width: MediaQuery.of(context).size.width - 30.0,
        height: 50.0,
        child: Card(
          color: Colors.lightBlue,
          elevation: 6.0,
          child: Center(
            child: Text('登陆', style: TextStyle(fontSize: 18.0, color: Colors.white)),
          )
        )
      ),
      onTap: (){
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(builder: (context) => HomePage()),
                (route) => route==null
        );
      },
    );
  }
  
}
复制代码

说明一下布局:less

  • 主体引入一个Column Widget
  • 第一个子Widget是一个logo图片,它被Padding Widget包裹着,咱们能够经过Paddingpadding属性,轻松的控制这个Widget位置和边距
  • 第二个和第三个子Widget是一个TextField Widget,和上面的图片同样,经过Padding Widget包裹着,很容易控制它们的边距
  • 第四个子Widget用的是一个Container,而后里面经过GestureDetector添加了点击事件,其实这里的登陆按钮,彻底能够经过button性质的Widget来作,这里只是想记录一下,给控件添加手势的功能

下面简单介绍一下几个简单的Widgetiphone

图片Widget

本地图片经过 pubspec.yaml 文件(位于项目根目录),来识别应用程序所用的图片ide

在根目录下新建一个images文件夹,存放图片使用函数

assets:
    - images/logo.png
    - images/background.png
复制代码

代码中能够直接引用,和iOS开发中的使用相似:Image.asset('images/logo.jpg')

网络图片的加载,看一下加载网络图片的方法Image.network('图片连接'),也很简单。

TextField Widget

最简单的输入框TextField(),只要这一句话,输入框其实就有了

经过项目里的代码能够看到,TextField里有个controller属性,经过这个来获取TextField的值:controller.text

作iOS的小伙伴们都知道iOS中的TextField属性中有个placeholder属性,那么这里能够经过decoration里的labelText设置这个值。

通常的密码输入框,咱们都是隐式显示,也就是▪️▪️▪️▪️来表示。obscureTexts设置为true便可。

还能够在左侧添加一个icon,代码中也能够看到用法。

有兴趣的小伙伴能够经过源码里的属性值,来了解这个Widget

本人项目中使用了不少圆角矩形的边框,这里有点坑,下面看下代码:

import 'package:flutter/material.dart';

class TextFieldView extends StatelessWidget {
  Widget borderTextField() {
    return TextField(
      decoration: InputDecoration(
        contentPadding: EdgeInsets.all(15.0),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(8.0),
          borderSide: BorderSide(color: Colors.red, width: 10.0, style: BorderStyle.solid)
        )
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('TextField')),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(15.0),
          child: borderTextField(),
        ),
      ),
    );
  }
}
复制代码

效果图:

可能,细心的小伙伴们已经发现了问题
borderSide: BorderSide(color: Colors.red, width: 10.0, style: BorderStyle.solid),这句代码对边框的设置毫无做用,这里的输入框,并非咱们想要的

好在坑已被前人填满,:边框颜色解决方案

因此正确的代码姿式应该是:

Widget borderTextField() {
    return Theme(
      data: ThemeData(primaryColor: Colors.red, hintColor: Colors.blue),
      child: TextField(
        decoration: InputDecoration(
            contentPadding: EdgeInsets.all(15.0),
            border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(8.0),
                // 下面方法无效
//                borderSide: BorderSide(color: Colors.red, width: 10.0, style: BorderStyle.solid)
            )
        ),
      ),
    );
  }
复制代码

效果图:

再者就是边框的粗细改变,暂时没有找到合适的方法,可是能够经过重构的方式,请看代码:

import 'package:flutter/material.dart';

class TextFieldView extends StatelessWidget {

  Widget borderTextField() {
    return Container(
      padding: const EdgeInsets.all(5.0),
      height: 40.0,
      decoration: BoxDecoration(
        color: Colors.white70,
        border: Border.all(color: Colors.yellow, width: 5.0),
        borderRadius: BorderRadius.circular(8.0)
      ),
      child: TextFormField(
        decoration: InputDecoration.collapsed(hintText: '请输入内容'),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('TextField')),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(15.0),
          child: borderTextField(),
        ),
      ),
    );
  }
}
复制代码

效果图:

页面跳转及路由

Navigator

Navigator继承StatefulWidget,它也是小组件,有不少相关静态函数,能够帮助咱们达到页面跳转和数据交互的功能:

  • push 将设置的route信息推送到Navigator上,实现页面跳转
  • of 主要是获取Navigator最近实力的好状态
  • pop 返回到上个页面
  • canPop 判断是否能够导航到新页面
  • popAndPushNamed 指定一个路由路径,并导航到新页面
  • popUntil 反复执行pop知道该函数的参数predicate返回true为止
  • pushAndRemoveUntil 将给定路由推送到Navigator,删除先前的路由,直到该函数的参数predicate返回true为止
  • pushNamed 将命名路由推送到Navigator
  • pushNamedAndRemoveUntil 将命名路由推送到Navigator,删除先前的路由,直到该函数的参数predicate返回true为止。
  • pushReplacement 路由替换。
  • pushReplacementNamed 这个也是替换路由操做。推送一个命名路由到Navigator,新路由完成动画以后处理上一个路由。
  • removeRoute 从Navigator中删除路由,同时执行Route.dispose操做。
  • removeRouteBelow 从Navigator中删除路由,同时执行Route.dispose操做,要替换的路由是传入参数anchorRoute里面的路由。
  • replace 将Navigator中的路由替换成一个新路由。
  • replaceRouteBelow 将Navigator中的路由替换成一个新路由,要替换的路由是是传入参数anchorRoute里面的路由。

路由的操做方式

使用Navigator.push实现发送路由,Navigator.pop返回上一个页面。

push函数的有两个:上下文context、Route。这里使用的是MaterialPageRoute,该类必需要传入一个闭包函数WidgetBuilder,参数是 BuildContext对象,咱们使用的是匿名函数的形式,加上箭头符号:builder: (context) => HomePage()

相关文章
相关标签/搜索