创建一个项目名为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引入:
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,//去除下边框
),
)
],
);
}
}
布局的效果:
验证码倒计时功能:
用到的是GestureDetector()组件,它是一个用于手势识别的功能性组件,我们通过它可以来识别各种手势.
接着把写好的验证码组件丢进GestureDetector里去,在onTap事件里用setState将定义的文本值进行修改,定义每隔1秒进行修改,就实现了倒计时效果.
核心代码:
效果
当然,定时器还需要优化:1.增加秒数为0的秒数不能为负的判断;2.增加秒数为0时要清除定时器;3.增加当秒数为0的时候才执行点击定时器的方法,实现秒数不到0时只能单次点击.
补充:flutter中网络请求的操作过程:
但实际更多用的是第三方请求库,查找方法:
flutter包链接,里面搜索即可.
比如使用bio库发起请求,安装如下:
保存后它会自动下载,使用案例:
本人用的是1.0.17版本,遇到的一个坑,报错:No address associated with hostname,解决办法:是网络问题,重启模拟器即可.
验证码按钮增加有手机号才执行定时器任务;登录按钮要做手机和验证码都有值判断;
验证点击:手机号username有值才执行
登录按钮:如果手机号和验证码输入框值都为空,不可点击.
在lib/module/config.dart写我们封装的静态内容:目前是封装了基地址
在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组件即可.
登录成功后的token我们是把它存在文件里的,在flutter package里的数据持久化插件shared_preferences(pub.dev官网可以找到这个插件)使用方法:安装,引入包,参照官网把setInt改为setString即可(用法跟本地存储差不多)
同时,用数据存储将token加在请求头里:
为了方便,我们的token是直接放在请求头里,所以我们统一放在封装的函数里,让它每次请求都带上这个token.添加方法:dio.options.headers[‘Authorization’]= prefs.getString(‘token’)??’ ',解释这里的"Authorization"跟后台约定好变量名,??是短路运算.
如果有登录去首页,没登录跳转到登录页
在公共封装里定义一个方法,在这个方法里返回一个token,然后在main方法里先执行.核心代码如下:
准备一个要跳转的首页:
初始化,创建DOM,销毁
比如我们在没有结束倒计时的时候是可以清楚定时器的.
源码地址:github.com:huanggengzhong/hmtt-app.git