Flutter從入門到奔潰(一):擼一個登陸界面

Flutter從入門到奔潰(一):擼一個登陸界面

前記

跨平臺開發目前有3種途徑:ReactNative,Weex,Flutter,至於他們之間的區別以及如何取捨,我以爲這在移動端工程師的圈子裏已經討論爛了吧,這裏就不贅述了,我就說下個人見解: 千萬!千萬!!千萬!!!不要試圖覺得你能夠踩完weex的坑。 見解完畢,咱們來開始接觸Flutter吧! Flutter是谷歌爸爸的新一代開發語音,主打的也是ios以及android兩個端,可是不只僅是侷限於這個,Flutter也是谷歌爸爸下一代操做系統的指定開發工具,身爲安卓🐶,緊跟谷歌爸爸老是沒錯的,爲此我仍是以爲拋棄rn,weex這些es6的,專心投入dart的懷抱(不是由於我討厭js和css)。css

學習指標

由於我比較懶...並且我是項目型驅動的懶鬼,個人學習方式能夠總結爲: 作項目+踩坑+填坑+踩坑+填坑...+罵娘=掌握一門知識 因此咱們用flutter來作一個項目吧!android

環境搭建

按照官網教程就能夠了,過幾天我寫個詳細點的ios

基礎介紹

我也不是很基礎...等我整明白了再出個詳細點es6

weight介紹

同上weex

登陸界面的實現

頁面邏輯講解

870957617161924503.jpg

咱們能夠看到頁面很簡潔:app

  • 一個logo
  • 一個帳號輸入框
  • 一個密碼輸入框
  • 一個登陸按鈕

如今咱們把頁面拆解一下:less

  1. AppBar
  2. Body
    1. 帳號框
    2. 密碼框
    3. 登陸按鈕

能夠看到頁面主要分爲2個層級: 最頂層的(只針對於代碼層次的頂層,不包括window之類的層級)爲: AppBar(標題欄) Body(主體欄) 而Body裏面則包含了次級的widgetside

具體實現

咱們先貼代碼,而後進行具體的講解工具

import 'package:flutter/material.dart';

class LoginPage extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    return new _LoginPageState();
  }
}

class _LoginPageState extends State<LoginPage> {
  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: <Widget>[
            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: <Widget>[
            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了... 頁面從頭到底我用白話文梳理一下:

  1. 一個從頭開始排列的鋪滿父佈局的數值排列的多佈局父控件裏面有一串子Widgets
  2. 第一個子Widgets是一個img Widgets,他被padding Widgets包裹着,以便於讓它獲得padding的屬性
  3. 第二個子Widgets是一個TextFidld Widgets(Android佬們能夠把他當作EditText),它也被padding Widgets包裹着,提供了四邊的padding,同時它還經過InputDecoration設置了hint,經過controller設置了controller
  4. 第三個子Widgets同上,理論上應該抽取公共方法,第二個第三個不該該是copy過去的
  5. 第四個Widgets是一個FlatButton(實際上它上面還包裹着兩個Widgets),它經過被Container包裹獲得了寬高padding,margin的屬性;經過被card包裹獲得了陰影的屬性。

至此佈局完畢,總結一下: 第一次寫以爲很麻煩,特別麻煩! 第二次寫以爲還行,就是)){{{}}}看得眼睛痛 第三次寫以爲...挖草,神經病啊 第四次寫以爲...生活啊,反抗不了,你qj我吧 第五次寫以爲...咦,用着感受還有點點激動 第六次寫以爲,好像還挺方便 ... ... 第N次,爽!老子纔不要xml。

頁面交互

這個頁面交互很少,無非2個:

  1. 拿到TextField的值
  2. 相應FlatButton的點擊

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

不過還記得咱們剛剛定義的TextEditingController嗎?操做TextField通常都是經過操控Controller來實現的,而咱們最簡單最經常使用的就是

TextEditingController.text
// 等於EditText.getText()
複製代碼

而點擊事件可使用onPressed()

onPressed: () {
     print("the pass is" + _userNameController.text);
	            },
複製代碼

總結

  1. 一不當心又水了一篇,沒啥乾貨,由於我也是初學,邊學邊記錄
  2. Flutter挺不錯的,至少渲染方式不是跟weex(巨坑的!!!)和rn同樣,而是走本身的一套,這點我很看好,由於其實rn和weex的體驗並非特別好
  3. Flutter的listview在個人mx5上會有卡頓,我不知道是我沒有優化好代碼仍是怎麼樣...我先馬克,帶着這個問題繼續學習
  4. 乾巴爹
相關文章
相關標籤/搜索