Flutter头条项目开发(一.登录页,接口封装和缓存插件)

项目准备

创建项目

创建一个项目名为heima_app,在main.dart里写最基础代码:

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title:'黑马头条',//记得MaterialApp的title是无需Text组件的.
      home: Scaffold());
  }
}

登录页面

lib文件夹里创建login/login.dart文件,在主页main.dart中引用登录页.表单中使用到了有状态组件(创建至少要两个类StatefulWidget和State类),三行用的是Column上下布局,输入框用的是TextField组件,第二行是用的Expanded灵活布局,使输入验证码自适应,第三行也是放一个Container组件,里面用RaisedButton组件.
main.dart引入:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第1张图片

login.dart布局如下:

import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("登录"), elevation: 0.0
          //头部底下阴影
          ),
      body: Container(color: Colors.grey[200], child: Formregist()),
    );
  }
}

// 下面这两个类是有状态组件,它至少需要两个类:StatefulWidget类和State类
class Formregist extends StatefulWidget {
  @override
  _FormregistState createState() => _FormregistState();

  // createState()=>new _FormregistState();简写
}

class _FormregistState extends State<Formregist> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Container(
          //Padding和Container是差不多的,Container会多一点属性
          color: Colors.white,
          padding: EdgeInsets.symmetric(
              horizontal: 10.0, vertical: 5.0), //对称方式填,horizontal是左右,另一个是上下
          child: TextField(
            //输入框
            keyboardType: TextInputType.phone, //键盘输入类型
            decoration: InputDecoration(
                //用于控制TextField的外观显示,如提示文本、背景颜色、边框等。
                prefixIcon:
                    Icon(Icons.mobile_screen_share, color: Colors.grey), //输入图标
                focusedBorder: UnderlineInputBorder(
                    //聚焦边框
                    borderSide: BorderSide(color: Colors.black45)),
                enabledBorder: UnderlineInputBorder(
                    //无焦边框
                    borderSide: BorderSide(color: Colors.black45)),
                hintText: "请输入手机号码", //默认文本
                hintStyle: TextStyle(color: Colors.black38, fontSize: 14.0)),
          ),
        ),
        Container(
            color: Colors.white,
            child: Row(
              children: <Widget>[
                Expanded(
                  //左边是灵活布局
                  child: Container(
                    padding: EdgeInsets.symmetric(
                        horizontal: 10.0,
                        vertical: 5.0), //对称方式填,horizontal是左右,另一个是上下
                    child: TextField(
                      //输入框
                      keyboardType: TextInputType.phone, //键盘输入类型
                      decoration: InputDecoration(
                          //用于控制TextField的外观显示,如提示文本、背景颜色、边框等。
                          prefixIcon:
                              Icon(Icons.lock, color: Colors.grey), //输入图标
                          focusedBorder: UnderlineInputBorder(
                              //聚焦边框
                              borderSide: BorderSide.none),
                          enabledBorder: UnderlineInputBorder(
                              //无焦边框
                              borderSide: BorderSide.none),
                          hintText: "请输入验证码", //默认文本
                          hintStyle:
                              TextStyle(color: Colors.black38, fontSize: 14.0)),
                    ),
                  ),
                ),
                Container(
                  //右边验证码
                  alignment: Alignment.center,
                  width: 110.0,
                  height: 30.0,
                  decoration: BoxDecoration(
                      color:
                          Color.fromRGBO(237, 237, 237, 1.0), //记得透明度要double类型
                      borderRadius: BorderRadius.circular(100.0)),
                  child: Text('获取验证码'),
                ),
                SizedBox(
                  //右边再放个空盒子,占据一点空间
                  width: 10.0,
                )
              ],
            )),
      Container(
        height: 45.0,
        
        padding: EdgeInsets.symmetric(horizontal: 10.0),
        width: double.infinity,//占满宽
        margin:EdgeInsets.only(top:20.0),//只设置一个
        child: RaisedButton(
          child: Text('登录',style:TextStyle(
            color:Colors.white
          ),),
          onPressed: (){
            
          },
          color:Colors.blue,
          disabledColor:Colors.blue[200],
          elevation: 0.0,//去除下边框
        ),
      )
      ],
    );
  }
}

布局的效果:

Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第2张图片
验证码倒计时功能:
用到的是GestureDetector()组件,它是一个用于手势识别的功能性组件,我们通过它可以来识别各种手势.
接着把写好的验证码组件丢进GestureDetector里去,在onTap事件里用setState将定义的文本值进行修改,定义每隔1秒进行修改,就实现了倒计时效果.
核心代码:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第3张图片
效果
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第4张图片
当然,定时器还需要优化:1.增加秒数为0的秒数不能为负的判断;2.增加秒数为0时要清除定时器;3.增加当秒数为0的时候才执行点击定时器的方法,实现秒数不到0时只能单次点击.

补充:flutter中网络请求的操作过程:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第5张图片
但实际更多用的是第三方请求库,查找方法:
flutter包链接,里面搜索即可.
比如使用bio库发起请求,安装如下:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第6张图片
保存后它会自动下载,使用案例:

Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第7张图片
本人用的是1.0.17版本,遇到的一个坑,报错:No address associated with hostname,解决办法:是网络问题,重启模拟器即可.

增加校验输入框值判断:

验证码按钮增加有手机号才执行定时器任务;登录按钮要做手机和验证码都有值判断;
验证点击:手机号username有值才执行
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第8张图片
登录按钮:如果手机号和验证码输入框值都为空,不可点击.
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第9张图片

公共数据封装:

在lib/module/config.dart写我们封装的静态内容:目前是封装了基地址
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第10张图片
在module/pub.dart里写我们的公共方法:参数加[]代表可传可不传,在封装的请求方法里用switch-case来判断是哪种请求方式相应的返回不同的res.
module/pub.dart

import 'package:dio/dio.dart'; //第三方dio接口请求要用到的包
import 'package:heima_app/moudle/config.dart'; //引入自己的基地址文件

Dio dio = new Dio();

class PubMoudle {
  static httpRequest(method, url, [data]) async {
    //[]代表可传可不传
    try {
      Response response;
      switch (method) {
        case 'get':
          response = await dio.get(Config.baseUrl + url,data:data);
          break;
        case "post":
          response = await dio.post(Config.baseUrl + url,data:data);
          break;
      }
      return response;
    } catch (err) {
      //错误
      print(err);
    }
  }
}

使用:
同时增加了验证码获取提示和登录成功提示:
提示直接使用Scaffold组件(需要调用of传递上下文)里的showSnackBar组件即可.
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第11张图片

数据存储:

登录成功后的token我们是把它存在文件里的,在flutter package里的数据持久化插件shared_preferences(pub.dev官网可以找到这个插件)使用方法:安装,引入包,参照官网把setInt改为setString即可(用法跟本地存储差不多)
同时,用数据存储将token加在请求头里:
为了方便,我们的token是直接放在请求头里,所以我们统一放在封装的函数里,让它每次请求都带上这个token.添加方法:dio.options.headers[‘Authorization’]= prefs.getString(‘token’)??’ ',解释这里的"Authorization"跟后台约定好变量名,??是短路运算.
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第12张图片
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第13张图片

用路由实现登录页跳转到首页:

使用的是删除了返回的跳转
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第14张图片

检查用户是否登录

如果有登录去首页,没登录跳转到登录页
在公共封装里定义一个方法,在这个方法里返回一个token,然后在main方法里先执行.核心代码如下:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第15张图片
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第16张图片
准备一个要跳转的首页:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第17张图片

flutter生命周期:

初始化,创建DOM,销毁
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第18张图片
比如我们在没有结束倒计时的时候是可以清楚定时器的.
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第19张图片

遇到的坑点:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第20张图片
最终效果:
Flutter头条项目开发(一.登录页,接口封装和缓存插件)_第21张图片

源码地址:github.com:huanggengzhong/hmtt-app.git

你可能感兴趣的:(十八.Flutter)