最近想学习下Flutter,于是利用demo学习一下官网的枯燥内容,
今天就用一个简单的登录页来开始Flutter的入门篇-Views!希望做完这个demo,大家就掌握了官网第一章的粗略内容,为接下来的玩游戏赢得了宝贵的。
这篇文章适合哪些人?
-
1.有安卓开发经验想入门Flutter的码农们。
-
2.不喜欢看书又想学到知识的“懒人”们。
-
3.刚打完游戏或浪费时间后心里内疚的“励志者”们。
-
4.正在蹲坑或者经常坐公交、地铁的掘金用户们。
-
5.看到最后一条的你们。
看完这篇你能学到什么?
-
1.修改控件内容
-
2.布局如此精(luo)妙(suo)
-
3.移除添加一个控件
-
4.给控件加上特效!kuang!
-
5.在canvas上画个啥
-
6.一个简单的自定义控件
-
7.缓解“不因虚度年华而悔恨”
我准备怎么讲这些东西呢?
兴趣是最好的老si!既然标题是“跟官网做demo”,所以想了一下就准备一个登录界面,通过这个简单的demo来一条条学习以上几点,如果哪点没覆盖到可以在评论区留言。至于有的人担心上厕所的时间看不完,放心,官网没有涉及的肯定不会讲。

flutter.dev/docs/get-st…
今天呢,我们要讲的这是这块内容:

首先简单地设计一下,一个提供两种方式的登录界面。

首先我们解决第一个问题,上图的什么输入框、按钮在Flutter中是什么?
Widget!
翻译成白话文就是组件控件的意思。
比如说一个简单的输入框是这样的:
TextField(
decoration: InputDecoration(hintText: "请输入手机号"),
controller: userNameController,
),
TextField(
decoration: InputDecoration(hintText: "请输入密码"),
controller: passwordController,
obscureText: true,
),
一个按钮是这样的:
child: MaterialButton(
child: Text("验证码登录"),
textColor: Colors.blue,
onPressed: () {
_switchLoginType(LOGIN_TYPE_CODE);
},
),
当然还有很多其他的组件,一种组件也有不同的样式,需要的时候再去官网查一下好了。
api.flutter.dev/flutter/wid…
更简单的方式直接上网查,比如密码输入框如何设置密文:

了解单个控件怎么弄出来的以后,就可以布局了,即规定每个控件应该出现在什么位置以及组件之间的嵌套关系。

在安卓中,我们有线性布局、相对布局、约束布局、表格以及流布局等八拉八拉的,Flutter也应有尽有。
比如我们登录界面的两个输入框以及登录方式是线性垂直排列,即放在一个叫Column的组件中。



值得一提的是,Flutter中的布局与其他平台还是细微差别,比如对齐方式在其他平台也就是一个属性,但是在Flutter中是一个组件。
好了,GET上面两个知识点后姑且认为你们知道如何进行简单的布局了,我们再继续看。
在登录页中,对于已经登录过的账号,下次登录时都会预先设置用户名,这里便有个知识点-如何更新组件内容。
我们可以给登录页预先设置个手机号。在Android中,我们直接拿到组件再调用setText方法就可以了,但是Flutter中有点麻烦,必须先给TextField设置个TextEditingController,然后调用其setText方法。


好了,再说一说登录方式切换,这便是官网讲到的添加/移除组件了。
我们可以回想下在Android中是怎么做的,通常的做法是把两种登录方式的布局都写上,然后根据点击事件来决定哪块内容显示隐藏。
一个道理!
比如我的“账号密码登录”和“验证码登录”都在布局中,通过loginType这个成员变量来控制显示什么布局。
/// 根据输入方式切换输入框布局
_inputAndLoginTypeArea() {
if (LOGIN_TYPE_PASSWORD == loginType) {
return _mobileAndPassword();
} else if (LOGIN_TYPE_CODE == loginType) {
return _mobileAndCode();
} else {
// 处理异常情况
}
}
然后把这个方法设置到之前的输入框位置。



下面我们看下动画,我们知道,一般耗时操作都会有个等待提示,在这个demo中,当登录按钮点击的时候,会出现一个等待对话框,在对话框中我们做一个简单的旋转动画。
和Android一样,Flutter也提供了各种动画,比如位移、旋转、淡入出等,具体可参考https://flutter.dev/docs/development/ui/animations,今天我们讲RotationTransition和CurvedAnimation。
在我们的demo中,我们使用了旋转动画来演示loading效果。

讲完了动画,我们再看看Canvas绘制。
可是……这个demo需要用到Canvvas吗?可以。比如验证码倒计时功能我们就可以用canvas来弄,只是,真实项目中用这个的确有点大材小用的意思哈。
void paint(Canvas canvas, Size size) {
final textStyle = TextStyle(
color: Colors.white,
fontSize: 16,
);
final textSpan = TextSpan(
text: '$number',
style: textStyle,
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.rtl,
);
textPainter.layout(
minWidth: 0,
maxWidth: 20,
);
final offset = Offset(-10, -5);
textPainter.paint(canvas, offset);
}
这个方法是覆盖了CustomPainter中的paint(Canvas canvas, Size size),作用与View的onDraw(Canvas canvas)方法类似,无非就是用一个painter把内容(形状、文字等)绘制到canvas上,用法与Android也是大同小异。
最后,再来看看自定义控件,在Android中,我们继承View就可以叫做自定义控件,比如extends Button或者extends ImageView等,在Flutter中,我们当然也可以自定义控件,只不过需要extends Widget罢了。比如在下面的代码中我们写了一个发送验证码的控件。
class CodeButtonState extends State<CodeButton> {
int number = 60;
bool isRepeat = false;
Timer timer;
Duration oneSec = const Duration(seconds: 1);
bool isPressed = false;
@override
Widget build(BuildContext context) {
return MaterialButton(
color: Colors.blue,
textColor: Colors.white,
child: _child(),
onPressed: () {
_countDown();
},
);
}
_child() {
if (number <= 0) {
if (this.isRepeat) {
return Text("重新发送");
}
} else if(number == 60){
return Text("发送验证码");
} else {
return CustomPaint(
painter: DrawNumberPainter(number),
);
}
}
/// 倒计时
_countDown() {
if(isPressed) {
return;
}
isPressed = true;
timer = new Timer.periodic(
oneSec,
(Timer timer) => setState(
() {
if (number <= 0) {
timer.cancel();
setState(() {
isPressed = false;
this.isRepeat = true;
});
} else {
setState(() {
this.number = number - 1;
});
}
},
),
);
}
@override
void dispose() {
timer.cancel();
super.dispose();
}
}
这样,在代码中我们只需要把这个控件作为child放进去就好了。
好了,今天通过demo和大家走马观花地把官网中Views相关内容理了一遍,后面章节中会继续通过这个demo来理下Intent相关内容,至于等到猴年马月要看老夫哪天不996聊〜〜