Flutter从入门到奔溃(一):撸一个登录界面

前记

跨平台开发目前有3种途径:ReactNative,Weex,Flutter,至于他们之间的区别以及如何取舍,我觉得这在移动端工程师的圈子里已经讨论烂了吧,这里就不赘述了,我就说下我的看法:

千万!千万!!千万!!!不要试图以为你可以踩完weex的坑。

看法完毕,我们来开始接触Flutter吧!

Flutter是谷歌爸爸的新一代开发语音,主打的也是ios以及android两个端,但是不仅仅是局限于这个,Flutter也是谷歌爸爸下一代操作系统的指定开发工具,身为安卓🐶,紧跟谷歌爸爸总是没错的,为此我还是觉得抛弃rn,weex这些es6的,专心投入dart的怀抱(不是因为我讨厌js和css)。

学习指标

因为我比较懒...而且我是项目型驱动的懒鬼,我的学习方式可以总结为:

做项目+踩坑+填坑+踩坑+填坑...+骂娘=掌握一门知识

所以我们用flutter来做一个项目吧!

环境搭建

按照官网教程就可以了,过几天我写个详细点的

基础介绍

我也不是很基础...等我整明白了再出个详细点

weight介绍

同上

登录界面的实现

页面逻辑讲解


870957617161924503.jpg

我们可以看到页面很简洁:

一个logo

一个账号输入框

一个密码输入框

一个登录按钮

现在我们把页面拆解一下:

AppBar

Body

账号框

密码框

登录按钮

可以看到页面主要分为2个层级:

最顶层的(只针对于代码层次的顶层,不包括window之类的层级)为:

AppBar(标题栏)

Body(主体栏)

而Body里面则包含了次级的widgets

具体实现

我们先贴代码,然后进行具体的讲解

import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
@override
State createState() {
return new _LoginPageState();
}
}
class _LoginPageState extends State {
var leftRightPadding = 30.0;
var topBottomPadding = 4.0;
var textTips = new TextStyle(fontSize: 16.0, color: Colors.black);
var hintTips = new TextStyle(fontSize: 15.0, color: Colors.black26);
static const LOGO = "images/oschina.png";
var _userPassController = new TextEditingController();
var _userNameController = new TextEditingController();
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("登录", style: new TextStyle(color: Colors.white)),
iconTheme: new IconThemeData(color: Colors.white),
),
body: new Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
new Padding(
padding: new EdgeInsets.fromLTRB(
leftRightPadding, 50.0, leftRightPadding, 10.0),
child: new Image.asset(LOGO),
),
new Padding(
padding: new EdgeInsets.fromLTRB(
leftRightPadding, 50.0, leftRightPadding, topBottomPadding),
child: new TextField(
style: hintTips,
controller: _userNameController,
decoration: new InputDecoration(hintText: "请输入用户名"),
obscureText: true,
),
),
new Padding(
padding: new EdgeInsets.fromLTRB(
leftRightPadding, 30.0, leftRightPadding, topBottomPadding),
child: new TextField(
style: hintTips,
controller: _userPassController,
decoration: new InputDecoration(hintText: "请输入用户密码"),
obscureText: true,
),
),
new Container(
width: 360.0,
margin: new EdgeInsets.fromLTRB(10.0, 40.0, 10.0, 0.0),
padding: new EdgeInsets.fromLTRB(leftRightPadding,
topBottomPadding, leftRightPadding, topBottomPadding),
child: new Card(
color: Colors.green,
elevation: 6.0,
child: new FlatButton(
onPressed: () {
print("the pass is" + _userNameController.text);
},
child: new Padding(
padding: new EdgeInsets.all(10.0),
child: new Text(
'马上登录',
style:
new TextStyle(color: Colors.white, fontSize: 16.0),
),
)),
),
)
],
));
}
}

现在我们可以看到整个的布局了,怎么说呢...对于一个写习惯了android的人来说,这种代码风格还真的是适应不了,特别是一串一串一串的 ),)),]})},说实在的,我很怀念xml,甚至是kotlin。

整个页面的基础

因为页面的需要变动的,所以我们使用了**StatefulWidget *,而StatefulWidget 与StatelessWidget *的区别,请看我之前的博文。

在State的build方法中,我们开始进行页面的构建:

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar:new AppBar(),
body:new Column(),
)
}

其中AppBar放导航信息,

Body放主体信息,

主体子widgets的构建

body: new Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
new Padding(
padding: new EdgeInsets.fromLTRB(
leftRightPadding, 50.0, leftRightPadding, 10.0),
child: new Image.asset(LOGO),
),
new Padding(
padding: new EdgeInsets.fromLTRB(
leftRightPadding, 50.0, leftRightPadding, topBottomPadding),
child: new TextField(
style: hintTips,
controller: _userNameController,
decoration: new InputDecoration(hintText: "请输入用户名"),
obscureText: true,
),
),
new Padding(
padding: new EdgeInsets.fromLTRB(
leftRightPadding, 30.0, leftRightPadding, topBottomPadding),
child: new TextField(
style: hintTips,
controller: _userPassController,
decoration: new InputDecoration(hintText: "请输入用户密码"),
obscureText: true,
),
),
new Container(
width: 360.0,
margin: new EdgeInsets.fromLTRB(10.0, 40.0, 10.0, 0.0),
padding: new EdgeInsets.fromLTRB(leftRightPadding,
topBottomPadding, leftRightPadding, topBottomPadding),
child: new Card(
color: Colors.green,
elevation: 6.0,
child: new FlatButton(
onPressed: () {
print("the pass is" + _userNameController.text);
},
child: new Padding(
padding: new EdgeInsets.all(10.0),
child: new Text(
'马上登录',
style:
new TextStyle(color: Colors.white, fontSize: 16.0),
),
)),
),
)
],
));

页面布局看得是真糟心...此时我又很怀念xml了...

页面从头到底我用白话文梳理一下:

一个从头开始排列的铺满父布局的数值排列的多布局父控件里面有一串子Widgets

第一个子Widgets是一个img Widgets,他被padding Widgets包裹着,以便于让它得到padding的属性

第二个子Widgets是一个TextFidld Widgets(Android佬们可以把他看成EditText),它也被padding Widgets包裹着,提供了四边的padding,同时它还通过InputDecoration设置了hint,通过controller设置了controller

第三个子Widgets同上,理论上应该抽取公共方法,第二个第三个不应该是copy过去的

第四个Widgets是一个FlatButton(实际上它上面还包裹着两个Widgets),它通过被Container包裹得到了宽高padding,margin的属性;通过被card包裹得到了阴影的属性。

至此布局完毕,总结一下:

第一次写觉得很麻烦,特别麻烦!

第二次写觉得还行,就是)){{{}}}看得眼睛痛

第三次写觉得...挖草,神经病啊

第四次写觉得...生活啊,反抗不了,你qj我吧

第五次写觉得...咦,用着感觉还有点点激动

第六次写觉得,好像还挺方便

... ...

第N次,爽!老子才不要xml。

页面交互

这个页面交互不多,无非2个:

拿到TextField的值

相应FlatButton的点击

嗯...我找不到id,也找不到findViewById,也找不到String mAccount=mEdLoginAccout.getText.toString()... 扑街...

不过还记得我们刚刚定义的TextEditingController吗?操作TextField一般都是通过操控Controller来实现的,而我们最简单最常用的就是

TextEditingController.text
// 等于EditText.getText()
而点击事件可以使用onPressed()
onPressed: () {
print("the pass is" + _userNameController.text);
},

总结

一不小心又水了一篇,没啥干货,因为我也是初学,边学边记录

Flutter挺不错的,至少渲染方式不是跟weex(巨坑的!!!)和rn一样,而是走自己的一套,这点我很看好,因为其实rn和weex的体验并不是特别好

Flutter的listview在我的mx5上会有卡顿,我不知道是我没有优化好代码还是怎么样...我先马克,带着这个问题继续学习

干巴爹