bash, mkdir, rm, git, curl, unzip, which
複製代碼
flutter官網下載其最新可用的安裝包git
安裝包下載完成則能夠進行解壓github
unzip /指定解壓目錄/flutter_macos_v1.9.1+hotfix.4-stable.zip
複製代碼
# 使用pwd 命令查看目錄路徑
/Users/XXXXX/development/flutter
複製代碼
設置環境變量目的是以便咱們能夠運行flutter命令在任何終端會話中算法
肯定Flutter SDK的目錄,上一步咱們解壓獲取了flutter的路徑/Users/XXXXX/development/fluttermacos
打開(或建立) HOME 指的是 路徑是 /Users/用戶名XX/ )編程
vim $HOME/.bash_profile
複製代碼
export PUB_HOSTED_URL=https://pub.flutter-io.cn //國內用戶須要設置
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //國內用戶須要設置
//
export PATH=/Users/XXXXX/development/flutter/bin:$PATH
複製代碼
source $HOME/.bash_profile
注意: 若是你使用的是zsh,終端啓動時 ~/.bash_profile 將不會被加載,解決辦法就是修改 ~/.zshrc ,在其中添加:source ~/.bash_profile
複製代碼
flutter doctor
複製代碼
flutter upgrade
複製代碼
var name = 'maoqitian';
var number = 1;
複製代碼
final List _suggestions = new List<WordPair>();
final _suggestions = <WordPair>[];
複製代碼
//以下定義一個字體大小的值一直都是 18 ,不會改變
final _biggerFont = const TextStyle(fontSize: 18.0)
複製代碼
//定義一個返回 bool(布爾)類型的方法
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//轉換以下能夠忽略類型定義
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
//只有一個表達式的方法,你能夠選擇 使用縮寫語法來定義
// => expr 語法是 { return expr; } 形式的縮寫
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
複製代碼
//調用有可選命名參數方法 playGames
playGames(bold: true, hidden: false);
//playGames 方法
playGames({bool bold, bool hidden}) {
// ...
}
複製代碼
// 定義可選位置參數方法
String playGames (String from, String msg, [String sports]) {
var result = '$from suggest $msg';
if (sports != null) {
result = '$result playing $sports together';
}
return result;
}
// 不用可選參數
playGames('Bob', 'Howdy'); // 返回值 Bob suggest Howdy
//使用可選參數
playGames('I', 'Xiao Ming', 'basketball'); //返回值 I suggest Xiao Ming playing basketball together.
複製代碼
// 定義可選位置參數方法
String playGames (String from , String msg, [String sports = 'football']) {
var result = '$from suggest $msg';
if (sports != null) {
result = '$result playing $sports together';
}
return result;
}
playGames('I', 'Xiao Ming'); //返回值 I suggest Xiao Ming playing football together.
複製代碼
// Android studio 建立Demo 項目 main.dart 文件開頭
void main() => runApp(MyApp());
//能夠轉換爲
void main(){
runApp(MyApp());
}
複製代碼
static Future<ArticleListData> getArticleData(int pageNum) async{
String path = '/article/list/$pageNum/json';
Response response = await HttpUtils.get(Api.BASE_URL+path);
ArticleBaseData articleBaseData = ArticleBaseData.fromJson(response.data);
return articleBaseData.data;
}
複製代碼
先了解這麼多,更多Dart 相關內容能夠查看Dart語言官網json
在開始Flutter Hello world程序以前,做爲一名Android 開發者,首先咱們要認識到Flutter中沒有原生開發的XML,全部界面和邏輯代碼都在.dart文件中,Flutter給我提供了一套視覺、結構、平臺、和交互式的Widgets,因此在Flutter中一構架的一切界面都是Widgets。接下來咱們先看一個簡單的Hello World Flutter應用。vim
Android Studio 新建Flutter demo數組
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return new MaterialApp(
theme: ThemeData(
primaryColor: Colors.blueAccent,
),
home: new Scaffold(
appBar: new AppBar(
title: new Center(
child: new Text("Welcome to Flutter"),
)
),
body: DemoStatelessWidget("Flutter Hello World ! 無狀態的Widget"),
),
);
}
}
//無狀態 Widget
class DemoStatelessWidget extends StatelessWidget{
final String text;
//構造方法傳入 text 值
DemoStatelessWidget(this.text);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
constraints: BoxConstraints.expand(
height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
),
padding: const EdgeInsets.all(8.0),
color: Colors.blue[600],
alignment: Alignment.center,
child: Text(text,
style: Theme.of(context)
.textTheme
.display1
.copyWith(color: Colors.white)),
transform: Matrix4.rotationZ(0.1),
);
}
}
複製代碼
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());
// StatelessWidget 無狀態的widget
class MyApp extends StatelessWidget { //Stateless widgets是不可變的, 這意味着它們的屬性不能改變 - 全部的值都是最終的.
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
//title: 'Welcome to Flutter',
theme: ThemeData(
primaryColor: Colors.blueAccent,
),
home: new RandomWords(),
);
}
}
//StatefulWidget 有狀態的widget
class RandomWords extends StatefulWidget{
@override
createState() => new RandomWordsState();
}
// 返回 顯示單詞對的ListView Widget
class RandomWordsState extends State<RandomWords> {
//保存建議的單詞對列表(變量如下劃線(_)開頭,在Dart語言中使用下劃線前綴標識符,會強制其變成私有的) final _suggestions = <WordPair>[];
final List _suggestions = new List<WordPair>();
//設置字體大小的變量
final _biggerFont = const TextStyle(fontSize: 18.0);
// 保存喜歡單詞組的集合 set 集合不容許值重複
final Set _saved = new Set<WordPair>();
/// State 生命週期方法
@override
void initState() {
// state 初始化
super.initState();
}
@override
void didChangeDependencies() {
// 在 initState 以後調用,此時能夠獲取其餘 State
super.didChangeDependencies();
}
@override
void dispose() {
// state 銷燬
super.dispose();
}
@override
Widget build(BuildContext context) {
//return new Text(new WordPair.random().asPascalCase);
//返回單詞對的ListView。
return new Scaffold(
appBar: new AppBar(
title:new Center( //居中顯示
child: new Text('Flutter ListView'),
),
),
body: _buildSuggestions(),
);
}
//構建顯示建議單詞對的ListView。
Widget _buildSuggestions(){
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
// 對於每一個建議的單詞對都會調用一次itemBuilder,而後將單詞對添加到ListTile行中
// 在偶數行,該函數會爲單詞對添加一個ListTile row.
// 在奇數行,該函數會添加一個分割線widget,來分隔相鄰的詞對。
//itemBuilder 值是一個匿名回調函數, 接受兩個參數- BuildContext和行迭代器i。迭代器從0開始,
// 每調用一次該函數,i就會自增1,對於每一個建議的單詞對都會執行一次。該模型容許建議的單詞對列表在用戶滾動時無限增加。
itemBuilder: (context,i){
// 在每一列以前,添加一個1像素高的分隔線widget
if(i.isOdd) return new Divider();
// 語法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),好比i爲:1, 2, 3, 4, 5
// 時,結果爲0, 1, 1, 2, 2, 這能夠計算出ListView中減去分隔線後的實際單詞對數量
final index = i~/2;
if(index >= _suggestions.length){
// 若是是建議單詞列表中最後一個單詞對 接着再生成10個單詞對,而後添加到建議列表
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
}
);
}
//建立 ListTile中顯示每一個新詞對
Widget _buildRow(WordPair suggestion) {
//獲取是否保存了該單詞狀態
final isSaved = _saved.contains(suggestion);
return new ListTile(
// 設置 標題
title: new Text(
suggestion.asPascalCase,
style: _biggerFont,
),
//圖標
trailing: new Icon(
//星型圖標狀態
isSaved ? Icons.favorite : Icons.favorite_border,
color: isSaved ? Colors.deepOrange : null ,
),
onTap: (){ // 當用戶點擊 ListTile 擊時, ListTile 會調用它的onTap回調
setState(() { //調用setState() 會爲State對象觸發build()方法,從而致使對UI的更新
if(isSaved){
_saved.remove(suggestion);
}else{
_saved.add(suggestion);
}
});
},
);
}
}
複製代碼
如上代碼,將原來的無狀態Widget改爲了StatefulWidget,並在build中構建ListView,到此你可能有疑惑,不是說有狀態的Widget,怎麼仍是建立Widget,有狀態如何體現呢? 別急,咱們看到_buildRow方法,方法中構建了ListTile 這個Widget,它響應點擊事件回到爲onTap方法,也就是當咱們點擊ListTile,咱們在onTap方法中就能夠調用setState方法來動態改變頁面顯示,也就是改變桃心收藏按鈕變化(注意setState方法須要在State類中才能調用)。bash
State 是有周期的,其中包括三個函數:網絡
佈局名稱 | 特色描述 |
---|---|
Container | 擁有單個子元素的佈局widget,能夠靈活設置 |
Padding | 擁有單個子元素,給其子widget添加指定的填充 |
Center | 將其子widget居中顯示 |
Align | 將其子widget對齊,並能夠根據子widget的大小自動調整大小。 |
Row | 能夠擁有多個子元素,在水平方向上排列子widget的列表,和原生控件 LinerLayout orientation="horizontal" 相似 |
Column | 能夠擁有多個子元素,在豎直方向上排列子widget的列表,和原生控件 LinerLayout orientation="vertical" 相似 |
Stack | 能夠擁有多個子元素,容許其子widget簡單的堆疊在一塊兒 |
Flow | 實現流式佈局算法的widget |
ListView | 可滾動的列表控件 |
Widget名稱 | 特色描述 |
---|---|
MaterialApp | 封裝了應用程序實現Material Design所須要的一些widget,由前面demo能夠發現它通常爲應用頂層入口widget |
Scaffold | Material Design佈局結構的基本實現。此類提供了用於顯示drawer、snackbar和底部sheet的API。 |
Appbar | 通常和Scaffold結合使用,能夠設置頁面標題和各類按鈕等(Toolbar) |
BottomNavigationBar | 底部導航條,能夠很容易地在tap之間切換和瀏覽頂級視圖 |
Drawer | 和Scaffold結合使用,從Scaffold邊緣水平滑動以顯示應用程序中導航連接的Material Design面板 |
RaisedButton | Material Design中的button,響應點擊事件(button) |
IconButton | 一個Material圖標按鈕,能夠設置icon,點擊時會有水波動畫 |
TextField | 文本輸入框 (EditText) |
image | 顯示圖片的widget(ImageView) |
Text | 單一格式的文本 (TextView) |
import 'package:flutter/material.dart';
class AppPage extends StatefulWidget {
@override
_AppPageState createState() => _AppPageState();
}
class _AppPageState extends State<AppPage> {
@override
Widget build(BuildContext context) {
return WillPopScope( ///經過WillPopScope 嵌套,能夠用於監聽處理 Android 返回鍵的邏輯。 WillPopScope 並非監聽返回按鍵,只是當前頁面將要被pop時觸發的回調
child: Container(),
onWillPop: () async{
return _doubleExitApp();
}
);
}
//雙擊返回 退出應用
bool _doubleExitApp(){
if (_lastPressedAt == null ||
DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
ToolUtils.ShowToast(msg: "再點一次退出應用");
//兩次點擊間隔超過1秒則從新計時
_lastPressedAt = DateTime.now();
return false;
}
//應用關閉直接取消 Toast
Fluttertoast.cancel();
return true;
}
///若是返回 return new Future.value(false); popped 就不會被處理
///若是返回 return new Future.value(true); popped 就會觸發
///這裏能夠經過 showDialog 彈出肯定框,在返回時經過 Navigator.of(context).pop(true);決定是否退出
/// 單擊提示退出
Future<bool> _dialogExitApp(BuildContext context) {
return showDialog(
context: context,
builder: (context) => new AlertDialog(
content: new Text("是否退出"),
actions: <Widget>[
new FlatButton(onPressed: () => Navigator.of(context).pop(false), child: new Text("取消")),
new FlatButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: new Text("肯定"))
],
));
}
}
複製代碼