一個Flutter的Demo
- 首先推薦兩篇文章,寫的非常的詳細,從中可以瞭解到原理,寫的非常的詳細!
-
Demo 的下載地址(正式包,使用Flutter命令打的正式包)
蒲公英.png
- App詳情

ezgif-2-c954a6dd5e.gif

ezgif-2-f3661cf95e.gif
App的頁面詳情
HomePage
;裡面嵌套了四個頁面,使用的是 TabBar
和 TabBarView
的組合,比如安卓中的 Fragment
Viewpager
- 1、首頁的第一頁使用豆瓣電影的介面,請求資料,並且展示出來了,工程中如何程式碼中如何使用依賴?如下程式碼所示
flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.0 fluttertoast: ^2.0.7 #"Packages get" 要去主動的 get 一次依賴 dio: ^v1.0.3 # 新增網路依賴
- 2、演示了圖片控制元件擺放
- 3、綜合列表的展示
- 4、其他控制元件的使用Demo

首頁.jpg

一些控制元件.jpg
* 首頁的關鍵程式碼 ``` //為給定的[子]控制元件建立預設選項卡控制器。 return new DefaultTabController( length: 5, child: new Scaffold( appBar: new AppBar( backgroundColor: Colors.black45, // title: titleWidget(), title: new Text("首頁",style: new TextStyle(color: Colors.white,fontSize: 22.00),), actions: <Widget>[ new IconButton( icon: new Icon(Icons.add_a_photo), onPressed: () { Navigator .of(context) .push(new MaterialPageRoute(builder: (context) { return new OtherPage(); })); }) ], bottom: new TabBar( isScrollable: true, labelStyle: new TextStyle(fontSize: 22.00,color: Colors.red), indicatorPadding:EdgeInsets.zero, labelColor: Colors.white, indicatorWeight:4.0, unselectedLabelColor: Colors.blueAccent, tabs: [ new Tab( text: "豆瓣電影", ), new Tab( text: "控制元件擺放", ), new Tab( text: "列表展示", ), new Tab( text: "其他控制元件展示", ), ]), ), body: new TabBarView(children: [new TabOne(), new TabTwo(),new TabThree(),new TabFroth()]), )); ```
SimilarWordsPage尋找近義詞Demo,就是一個點選按鈕,然後請求網路,重新整理頁面的流程。
- 1、使用了
TextField
相當於安卓中的Edittext
,只不過獲取值的時候有些變化new Expanded( child: new TextField( //不要主動彈起來 autofocus: false, controller: _textController, decoration: new InputDecoration.collapsed( hintText: "請輸入要查詢的詞", hintStyle: new TextStyle(color: Colors.red)), ),
- 2、如何退出頁面
Navigator.of(context).pop();
- 3、如何使用
Toast
,這裡我是使用了三方的依賴!底層原理是使用了反射,具體實現的方法,有興趣的同學可以看看String res = await _channel.invokeMethod('showToast', params);
Fluttertoast.showToast( msg: "輸入為空,請重新輸入", timeInSecForIos: 1, bgcolor: "#e74c3c", textcolor: '#ffffff');
- 4、帶框的Button的使用,具體請看實現的程式碼。
- 5、具體頁面如下

近義詞頁面.jpg
- 6、程式碼如下
import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_app/bean/DataBean.dart'; import 'package:fluttertoast/fluttertoast.dart'; class SimilarWordsPage extends StatefulWidget { @override State<StatefulWidget> createState() { return new SimilarWordsPageState(); } } class SimilarWordsPageState extends State<SimilarWordsPage> { List<DataBean> datas = []; static int i=0; final TextEditingController _textController = new TextEditingController(); @override Widget build(BuildContext context) { return new Scaffold( appBar: findAppBar(), backgroundColor: Colors.black12, body: findBody(), ); } findBody() { return new Container( child: new Scaffold( body: new ListView.builder( itemCount: datas.length, itemBuilder: (BuildContext context, int position) { i=position; return getRow(position); }, ), )); } Widget findAppBar() { return new AppBar( title: new Container( child: new Row( children: <Widget>[ new Container( child: new FlatButton.icon( onPressed: () { // 本來就在棧頂,退出會有顯示的問題 Navigator.of(context).pop(); }, icon: new Icon(Icons.close, color: Colors.white30), label: new Text(""), ), width: 60.0, ), new Expanded( child: new TextField( //不要主動彈起來 autofocus: false, controller: _textController, decoration: new InputDecoration.collapsed( hintText: "請輸入要查詢的詞", hintStyle: new TextStyle(color: Colors.red)), ), ), //點選事件的第一種實現的方式我覺得不太好 //new GestureDetector(child: new Icon(Icons.find_in_page),onTap: (){print("dd");}) // 這種點選時間有點效果 new IconButton( icon: new Icon(Icons.find_in_page), onPressed: () { print(_textController.text); if (_textController.text.isEmpty) { Fluttertoast.showToast( msg: "輸入為空,請重新輸入", timeInSecForIos: 1, bgcolor: "#e74c3c", textcolor: '#ffffff'); } else { FocusNode focusNode = new FocusNode(); FocusScope.of(context).requestFocus(new FocusNode()); Fluttertoast.showToast( msg: "查詢值為:" + _textController.text, timeInSecForIos: 1, bgcolor: "#e74c3c", textcolor: '#ffffff'); getApiData(_textController.text); focusNode.unfocus(); } }) ], ), decoration: new BoxDecoration( borderRadius: const BorderRadius.all(const Radius.circular(4.0)), color: Colors.white10), )); } Widget getRow(int i) { return new Padding( padding: new EdgeInsets.all(10.0), // child: new Text("Row ${datas[i].key}",style: new TextStyle(color: Colors.orange,fontSize: 18.00),) //Column 相當於 相對佈局Row 線性佈局 child: new Column( children: <Widget>[ new Padding( padding: new EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 5.0), child: new Row( children: <Widget>[ new Expanded( child: new OutlineButton( borderSide:new BorderSide(color: Theme.of(context).primaryColor), child: new Text('條目 = '+i.toString(),style: new TextStyle(color: Theme.of(context).primaryColor),), onPressed: (){}, ) ), ], ), ), new Container( child: new Text( "聯想到的詞:" + datas[i].key, style: new TextStyle(color: Colors.purple, fontSize: 12.00), ), padding: new EdgeInsets.all(10.0), ), new Container( child: new Text("聯想到詞的翻譯資訊:" + datas[i].message, style: new TextStyle(color: Colors.cyan, fontSize: 15.00)), padding: new EdgeInsets.all(10.0), ) ], ), ); } @override void initState() { super.initState(); // 網路請求 //http://dict-mobile.iciba.com/interface/index.php?c=word&m=getsuggest&nums=10&client=6&is_need_mean=1&word=sm //我的 Api的地址 getApiData("sm"); } // 網路請求 void getApiData(String tag) async { // 注意匯入的包的地方是import 'dart:io'; var httpClient = new HttpClient(); var url = "http://dict-mobile.iciba.com/interface/index.php?c=word&m=getsuggest&nums=20&client=6&is_need_mean=1&word=" + tag; var request = await httpClient.getUrl(Uri.parse(url)); var response = await request.close(); if (response.statusCode == HttpStatus.OK) { var jsonData = await response.transform(utf8.decoder).join(); setState(() { datas = DataBean.decodeData(jsonData); }); for (int i = 0; i < datas.length; i++) { print(datas[i].key); print(datas[i].message); } } } }
官方Demo

官方Demo.jpg
關於我

關於我.jpg
一些總結
-
widget
相當於View
,Widget
的例項僅僅存在每一幀之間,並且每一幀之間Flutter
都會主動的建立一顆Widget
樹用於下一幀的渲染。 -
Android
中View
是可變的,在Flutter
中的Widget
是不可變的。這種特性使得Flutter
中的Widget
變得十分輕量級 - 一個
Widget
會變化,那麼它就是有狀態的。但是如果一個子Widget
是有狀態的,但是其父Widget
是不可變的話父Widget
也可以是StatelessWidget
。 -
TatelessWidget
和StatefulWidget
的核心內容是一致的,它們都會在每一幀中被重構,不同之處在於StatefulWidget
有一個State
物件,它可以為StatefulWidget
在不同幀之間儲存資料。 -
Flutter
中UI
的佈局是通過在dart
檔案中構建Widget
樹來實現的。 - 在
Android
中,使用LinearLayout
使你的部件垂直或水平放置。在Flutter
中,你可以使用Row
或者Column
來實現相同的效果。 - 在
Flutter
中,最簡單的方法是使用ListView
。在Flutter
中,ListView
既是ScrollView
又是Android
中的ListView
。 - 通過使用
Column
,Row
和Stack
等Widget
的組合來實現RelativeLayout
的效果 -
Flutter
中,新增觸控監聽器有兩種方法 - 如果
Widget
支援事件檢測,則可以將一個函式傳遞給它並進行處理。例如,RaisedButton
有一個onPressed
引數 - 如果
Widget
不支援事件檢測,則可以將該Widget
包裝到GestureDetector
中,並將函式傳遞給onTap
引數。 -
GestureDetector
我們可以監聽廣泛的手勢 - 要充分利用應用程式中的
Material
風格的元件的話,可以把頂級部件MaterialApp
作為應用程式的入口。MaterialApp
作為一個比較方便的部件,包裝了許多實現了Material
風格所需要的部件(如Scaffold
)。MaterialApp
是在WidgetsApp
的基礎上進行實現的 -
Flutter
不會自動匯入包 -
Column
相當於 相對佈局Row
線性佈局 - 首頁的資料結構展示
-
HttpClient
匯入的包是io
裡面的 -
DEBUG
包要不正式包大很多Built build\app\outputs\apk\debug\app-debug.apk (31.9MB).
而正式包才8.4M
. - 解決的
Bug
的時候太痛苦了,Flutter
使用ide
,太痛苦了 - 在腦袋要構思出 這個佈局的整體的結構
- 關閉系統自帶的防火牆,重啟OK 由於需要出差,就是用的是筆記本開發,導致自己筆記本的防火牆沒有被關閉,真的是日了狗了, 解決防火牆 。
- MediaQuery.of(context).size.width / 4分之一的螢幕
-
MaterialApp
帶有Debug
的標記
感謝以下資料給與我的幫助
- Android 開發者參考
- Api的介面 查詢近義詞
- Api的介面 豆瓣電影
- 打包的流程