上一篇我們已經(jīng)配置完所有的Flutter環(huán)境近哟,那接下來(lái)開始創(chuàng)建第一個(gè)Flutter應(yīng)用。
1.打開IDEA選擇Flutter
然后創(chuàng)建項(xiàng)目填寫項(xiàng)目名稱,注意:項(xiàng)目名稱中不能包含大寫字母!!兰英!
2.此時(shí)我們可以在項(xiàng)目目錄中找到Android和iOS的項(xiàng)目
打開iOS應(yīng)用,創(chuàng)建一個(gè)唯一的bundleID供鸠,能在手機(jī)中運(yùn)行即可
3.創(chuàng)建文件畦贸,復(fù)制代碼
- 在
lib
下找到mian.dart
文件,刪除main下的所有代碼楞捂,替換為下面的代碼
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
child: new Text('Hello World'),
),
),
);
}
}
- 在項(xiàng)目目錄中找到
pubspec.yaml
薄坏,在文件中添加
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.0
english_words: ^3.1.0
但是在pubspec,yaml
中正林,發(fā)現(xiàn)只是缺少english_words: ^3.1.0
,添加這行代碼
然后單擊右上角的 Packages get這樣就會(huì)將依賴包安裝到項(xiàng)目中
控制臺(tái)中會(huì)顯示以下內(nèi)容
- 創(chuàng)建一個(gè)有狀態(tài)的
StatefulWidget
這個(gè)是用于展示ListView
,根據(jù)不同的狀態(tài)來(lái)展示不同的狀態(tài)下的ListView
颤殴。
import 'package:flutter/widgets.dart';
import 'package:fluttertest/RandomWordsState.dart';
//動(dòng)態(tài)組件類,用于顯示listview
class RandomWords extends StatefulWidget {
//返回狀態(tài),告訴widget不同情況下如何展示
@override
State<StatefulWidget> createState() {
return new RandomWordsStat();
}
}
- 構(gòu)建
ListView
創(chuàng)建RandomWordsState
類
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:fluttertest/RandomWords.dart';
import 'package:english_words/english_words.dart';
//State 是當(dāng) Widget 被渲染或者在其生命周期中狀態(tài)改變時(shí)觅廓,能同步讀到相關(guān)信息的對(duì)象。當(dāng)實(shí)例StatefulWidget 時(shí)
// 必須保證能正確使用 State.setState 來(lái)告知該 Widget的狀態(tài)發(fā)生了變化涵但。
class RandomWordsStat extends State<RandomWords>{
//Dart中加上 _表示私有化
final _suggestions = <WordPair>[]; //分析 1
final _saved = new Set<WordPair>();
final _biggerFont = const TextStyle(fontSize: 18.0); //分析 2
@override
Widget build(BuildContext context) {
return new Scaffold (
appBar: new AppBar(
title: new Text('Startup Name Generator'),
actions: <Widget>[ //右上角按鈕點(diǎn)擊事件杈绸,跳轉(zhuǎn)到下一個(gè)頁(yè)面,所以要實(shí)現(xiàn)`_pushSaved`這個(gè)方法
new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
],
),
body: _buildSuggestions(),
);
}
Widget _buildSuggestions() {
return new ListView.builder(
padding: const EdgeInsets.all(16.0),
// 對(duì)于每個(gè)建議的單詞對(duì)都會(huì)調(diào)用一次itemBuilder矮瘟,然后將單詞對(duì)添加到ListTile行中
// 在偶數(shù)行瞳脓,該函數(shù)會(huì)為單詞對(duì)添加一個(gè)ListTile row.
// 在奇數(shù)行,該函數(shù)會(huì)添加一個(gè)分割線widget澈侠,來(lái)分隔相鄰的詞對(duì)劫侧。
// 注意,在小屏幕上哨啃,分割線看起來(lái)可能比較吃力烧栋。
itemBuilder: (context, i) {
// 在每一列之前,添加一個(gè)1像素高的分隔線widget
//當(dāng)時(shí)奇數(shù)時(shí)返回true
if (i.isOdd) return new Divider();
// 語(yǔ)法 "i ~/ 2" 表示i除以2拳球,但返回值是整形(向下取整)审姓,比如i為:1, 2, 3, 4, 5
// 時(shí),結(jié)果為0, 1, 1, 2, 2祝峻, 這可以計(jì)算出ListView中減去分隔線后的實(shí)際單詞對(duì)數(shù)量
final index = i ~/ 2;
// 如果是建議列表中最后一個(gè)單詞對(duì)
if (index >= _suggestions.length) {
// ...接著再生成10個(gè)單詞對(duì)魔吐,然后添加到建議列表
_suggestions.addAll(generateWordPairs().take(10));
}
return _buildRow(_suggestions[index]);
}
);
}
Widget _buildRow(WordPair pair) {
final alreadySaved = _saved.contains(pair);
//listView中的行,相當(dāng)于cell
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
//右邊的圖標(biāo)
trailing: new Icon(
alreadySaved ? Icons.favorite : Icons.favorite_border,
color: alreadySaved ? Colors.red : null,
),
onTap: () {
setState(() {
if (alreadySaved) {
_saved.remove(pair);
} else {
_saved.add(pair);
}
});
},
);
}
//右上角跳轉(zhuǎn)
void _pushSaved() {
Navigator.of(context).push( // 分析 1//通過Navigator.of(context).push來(lái)跳轉(zhuǎn)頁(yè)面
new MaterialPageRoute( // 分析 2 跳轉(zhuǎn)的話我們需要一個(gè)路由
builder: (context) {
final tiles = _saved.map( //數(shù)據(jù),從set中獲取的數(shù)據(jù)
(pair) {
return new ListTile(
title: new Text(
pair.asPascalCase,
style: _biggerFont,
),
);
},
);
final divided = ListTile.divideTiles(
context: context,
tiles: tiles,
).toList();
return new Scaffold( // 分析 3 將要跳轉(zhuǎn)的頁(yè)面,body的內(nèi)容是一個(gè)listView.展示的數(shù)據(jù)
appBar: new AppBar(
title: new Text('Saved Suggestions'),
),
body: new ListView(children: divided),
);
},
),
);
}
}
在此處可以看到莱找,onTap
時(shí)調(diào)用了state.setState
酬姆,這時(shí)會(huì)告訴框架重繪RandomWords
這個(gè)widget
- 在main.dart中
import 'package:flutter/material.dart';
import 'package:fluttertest/RandomWords.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
home: new RandomWords(),
);
}
}
此時(shí)我們就可以在手機(jī)上運(yùn)行項(xiàng)目了。
雖說(shuō)這個(gè)小demo已經(jīng)出來(lái)了奥溺,但還是有一些不太了解的地方辞色,下面列出了我覺得需要注意的地方。
- 首先我們需要知道
main.dart
是程序的入口文件谚赎,類似iOS的AppDelegate
文件淫僻,而在main
文件中诱篷,默認(rèn)執(zhí)行的第一行代碼就是
void main() => runApp(new MyApp());
壶唤,也就是會(huì)最先執(zhí)行下面的代碼
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Startup Name Generator',
home: new RandomWords(),
);
}
}
-
StatelessWidget
StatefulWidget
這兩個(gè)是什么鬼,有什么區(qū)別棕所?-
StatelessWidget
是只有一種狀態(tài)的組件闸盔,我理解的意思是不會(huì)變化的控件 -
StatefulWidget
是有多種狀態(tài)的組件,例如在demo中琳省,點(diǎn)擊的心形按鈕發(fā)生改變迎吵,state的改變就會(huì)引起StatefulWidget
的重繪
-
-
Widget build(BuildContext context)
重寫這個(gè)函數(shù)是干什么躲撰?BuildContext
的作用是什么?- 首先要先解釋
widget
击费,這個(gè)可以理解為iOS中的基礎(chǔ)控件UIVIiew
拢蛋,存放渲染內(nèi)容、視圖布局信息蔫巩。然而Widget build
就是起構(gòu)建的方法谆棱,返回的Scaffold
就是widget
的布局信息。 -
BuildContext
看下文檔就知道這是一個(gè)抽象類圆仔,所以抽象類是不能直接調(diào)用方法的垃瞧,implement
或者extend
都可以
再往上翻,我們會(huì)看到BuildContext
的介紹坪郭,A handle to the location of a widget in the widget tree.
个从,翻譯過來(lái)就是widget在widget樹中位置的句柄,句柄是widget資源歪沃、內(nèi)存的標(biāo)示號(hào)嗦锐,所以我理解通過這個(gè)BuildContext
可以獲取或者更新對(duì)應(yīng)的widget
。
- 首先要先解釋
關(guān)于
Set
沪曙,這里默認(rèn)繼承的是LinkedHashSet
意推,是按照元素插入的順序迭代的,所以是有序的珊蟀,而不是HashSet
菊值,因?yàn)?code>HashSet是無(wú)序的。WordPair
你可以把他理解為變異的String育灸,當(dāng)然是有所不同的腻窒,WordPair是兩個(gè)String的拼接,在初始化的時(shí)候就已經(jīng)將first second賦值了磅崭。
asPascalCase first和seconde首字母大寫
asString 返回原始的string儿子,不做修改
asLowerCase first 和second的首字母都是大寫
asUpperCase 所有字母都大寫
asCamelCase first首字母小寫,second首字母大寫