該文已受權公衆號 「碼個蛋」,轉載請指明出處android
上一節介紹了 Dart
的一些語法,以及配置環境的網址,這節咱們就能夠開始瞭解下 Flutter
了git
主要包括 MaterialApp
、Scaffold
、Text
、Image
、Icon
、Button
以及 AppBar
部份內容,準備出發~github
新建 flutter 項目後,能夠看到 lib 下的 main.dart 中 void main() => runApp(MyApp());
這句就是程序的入口了。這裏能夠簡單看下源碼數據庫
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..attachRootWidget(app)
..scheduleWarmUpFrame();
}
///....
static WidgetsBinding ensureInitialized() {
if (WidgetsBinding.instance == null)
WidgetsFlutterBinding();
return WidgetsBinding.instance;
}
///....
void attachRootWidget(Widget rootWidget) {
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget
).attachToRenderTree(buildOwner, renderViewElement);
}
複製代碼
首先會建立一個 WidgetsBinding
單例對象,而後把傳入的 App 添加到 rootWidget
中,scheduleWarmUpFrame
方法比較長,這邊看下對該方法的註釋第一句就能瞭解方法的主要功能了markdown
Schedule a frame to run as soon as possible網絡
「安排框架儘快運行起來」(原諒我這渣英語,只能看懂不會翻譯..大概就是「快速啓動框架」的意思吧)app
接着看下 MyApp
這個類,繼承自 StatelessWidget
並在 build
方法返回一個 MaterialApp
實例,(偷偷講下,其實這邊還能夠返回 CupertinoApp
,這是一個 iOS 風格的 widget,基本上你看到部件帶 「Cupertino」的都是 iOS 風格的 widget,這裏先不講 iOS 風格的部件,目前 flutter 對 Cupertino 系列的 widget 支持不是很好,包括部件的廣度,多語言的支持等等方面都不是很友好,因此咱們仍是繼續看 MD 風格的 Android 部件吧~),這裏先看下 MaterialApp
的構造函數,介紹一些經常使用的參數框架
const MaterialApp({
Key key,
this.navigatorKey,
this.home, // 主界面的內容 widget
this.routes = const <String, WidgetBuilder>{}, // 帶 router 和路由跳轉有關
this.initialRoute,
this.onGenerateRoute,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.title = '', // *相似標題
this.onGenerateTitle, // 主要用於多語言狀況下,須要根據當前語言替換 title,須要使用該值
this.color, // 主題色,若是該值未設置,取 theme.primaryColor,未設置 theme 則取藍色
this.theme, // App 的主題風格,包括主題色,按鈕默認顏色等等
this.locale, // 帶 locale 的和多語言適配相關
this.localizationsDelegates,
this.localeListResolutionCallback,
this.localeResolutionCallback,
this.supportedLocales = const <Locale>[Locale('en', 'US')],
this.debugShowMaterialGrid = false,
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true, // debug 模式下,是否顯示 DEBUG 標示橫幅
})
複製代碼
MaterialApp
繼承自 StatefulWidget
,它和 MyApp
所繼承的類 StatelessWidget
,就是平常開發中,自定義部件一般繼承的抽象類了。less
StatelessWidget
是狀態不可變部件,經過其構建的部件通常用來展現固定內容,例如須要展現固定的功能按鈕列表,不須要根據不一樣界面狀態進行修改其展現內容StatefulWidget
是可改變狀態的部件,好比咱們須要經過網絡或者數據庫獲取數據,而後修改部件鎖展現的數據內容,則須要經過 StatefulWidget
來構建。固然,不是說 StatelessWidget
不能實現修改界面數據的功能,這就須要涉及到 狀態管理 的概念了,後面有機會再講,這邊先埋坑【坑1】進入 App
後就須要構建界面了,Flutter
提供了 Scaffold
來快速構建一個 MaterialDesign
風格的界面,仍是先看下 Scaffold
的構造函數吧,瞭解幾個比較經常使用的部分。ide
const Scaffold({
Key key,
this.appBar, // 界面頂部的那條欄,這邊須要返回一個 AppBar 實例
this.body, // 界面的內容部分
this.floatingActionButton, // 懸浮部分,能夠經過 floatingActionButtonLocation 設置位置
this.floatingActionButtonLocation,
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer, // 側滑抽屜部分,從左側滑出(應該和語言有關,和文字方向同向)
this.endDrawer, // 側滑抽屜部分,從右側滑出
this.bottomNavigationBar, // 底部導航欄,就是一般看到的底部 TAB 切換部件
this.bottomSheet, // 展現從底部彈出的,起到提示做用的,經過 showModalBottomSheet 展現
this.backgroundColor, // 界面的背景色
this.resizeToAvoidBottomPadding = true, // 避免 body 被底部彈出部件填充,例如輸入法鍵盤
this.primary = true, // 當前的 Scaffold 是否須要被展現在屏幕最上層
})
複製代碼
來張圖吧,簡潔明瞭
瞭解完 Scaffold
的總體構造後,咱們從上到下,經過構造函數來了解下各個 Widget
的使用方法
AppBar({
Key key,
this.leading, // 用於設置 AppBar 前置的按鈕,例如設置返回咱們須要的返回按鈕等
this.automaticallyImplyLeading = true, // 是否使用系統默認生成的按鈕,若是替換 leading 的默認按鈕,最好將該屬性設置成 false
this.title, // AppBar 所須要展現的組件,傳入一個 Widget 實例,一般使用 Text 展現一個標題
this.actions, // AppBar 末尾懸浮的一些操做組件,例如常見的會在末尾設置一個「...」按鈕,點擊彈出一個 menue 提供給用戶操做選擇
this.flexibleSpace, // AppBar 的背景,能夠設置顏色,背景圖等等
this.bottom, // bottom 用於展現頂部導航 TAB
this.elevation = 4.0,
this.backgroundColor, // AppBar 的背景色,若是隻須要修改顏色,能夠不經過 flexibleSpace 修改
this.brightness,
this.iconTheme, // 按鈕的默認樣式
this.textTheme, // 文字的默認樣式
this.primary = true,
this.centerTitle, // 是否將展現的 title 居中
this.titleSpacing = NavigationToolbar.kMiddleSpacing, // AppBar title 兩側的空白間隔
this.toolbarOpacity = 1.0,
this.bottomOpacity = 1.0,
})
複製代碼
在展現 AppBar
的 demo
以前,咱們先學習幾個基本的組件 Text
、Image
、Icon
、Button
分佈用於展現文字,圖片,圖標,按鈕
const Text(this.data, { // Text 須要展現的文字
Key key,
this.style, // 文字的樣式,包括顏色,大小,間距等等屬性,這邊就不繼續展現 TextStyle 構造函數了,否則我怕你們都不想繼續看了,稍後經過例子來講明
this.textAlign, // 文字的對齊方式,包括左對齊,右對齊,居中等,詳見 TextAlign 類
this.textDirection, // 文字方向,ltr(left to right) 或者 rtl(right to left)
this.locale,
this.softWrap, // 當文字一行顯示不完是否換行
this.overflow, // 若是超出限制的行數,以哪一種方式省略未展現的內容
this.textScaleFactor, // 文字縮放比例
this.maxLines, // 最多展現的行數
this.semanticsLabel,
})
複製代碼
說了那麼多,相信不少小夥伴都要急着擼代碼了吧,接着來展現一些 Text
的示例,接下來的例子都會直接替換 HomePage
內的展現內容,其他都是相同的,接下來請關注 Text
別的部件先忽略,後面會介紹,這邊先埋坑【坑2】
import 'package:flutter/material.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.lightBlue),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.only(top: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('綠色背景黑色文字展現',
style: TextStyle(
color: Colors.black, // 設置文字顏色,不可和 foreground 同時設置
fontSize: 24.0, // 字體大小
letterSpacing: 2.0, // 每一個字符之間的間隔
background: Paint()..color = Colors.green)), // 背景色
Text('這是一個帶紅色下劃線的文字展現',
style: TextStyle(
color: Colors.black,
fontSize: 24.0,
// 文字裝飾線,除了 underline 還有 overline, lineThrough,
// 不一樣的樣式小夥伴能夠經過本身修改代碼來查看
decoration: TextDecoration.underline,
// 文字裝飾線的類型,除了 solid 還有 double,dotted,dashed,wavy 可選
decorationStyle: TextDecorationStyle.solid,
// 裝飾線的顏色
decorationColor: Colors.red))
],
)),
));
}
}
複製代碼
該部分代碼查看源碼 text_main.dart
文件
最後的展現效果以下圖:
/壞笑 按照慣例,咱們仍是先看下 Image
的構造函數吧
const Image({
Key key,
// 一個 ImageProvider 實例,可是 ImageProvider 是一個抽象類,Flutter 已經給咱們提供以下
// AssetImage,NetworkImage,FileImage,MemoryImage 這四種圖片加載器,爲了方便調用
// 咱們能夠直接經過 Image.asset, Image.network, Image.file, Image.memory 簡化,
// 經過方法名,能夠看出分別從 asset 文件,網絡,文件,內存中加載圖片
@required this.image,
this.semanticLabel,
this.excludeFromSemantics = false,
this.width, // 圖片寬度
this.height, // 圖片高度
this.color, // 圖片背景色
this.colorBlendMode, // color 和圖片的混合模式(這個值比較多,能夠一個個嘗試)
this.fit, // 圖片填充方式 fill, cover, contain, fillWidth, fillHeight, scaleDown, none
this.alignment = Alignment.center, // 對齊方式
this.repeat = ImageRepeat.noRepeat, // 若未填充滿空間,重複展現的方式
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.filterQuality = FilterQuality.low,
})
複製代碼
好了好了,我知道大家又想本身寫代碼嘗試下了,在這以前,須要你先準備一張本地圖片,而後在項目的根目錄,也就是 lib
文件夾同層,建立一個新的文件夾,命名爲 images
,把你準備好的圖片放到這個目錄下。放好以後打開 pubspec.yaml
把圖片資源文件註冊下
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# 這邊註冊資源文件,之後有圖片文件也能夠只註冊 images 文件夾,會自動讀取內部的文件
assets:
- images/ali.jpg
複製代碼
註冊完成後,就能夠繼續愉快的擼代碼了~
class HomePage extends StatelessWidget {
final String _assetAli = 'images/ali.jpg';
final String _picUrl =
'https://timg05.bdimg.com/timg?wapbaike&quality=60&size=b1440_952&cut_x=143&cut_y=0&cut_w=1633&'
'cut_h=1080&sec=1349839550&di=cbbc175a45ccec5482ce2cff09a3ae34&'
'src=http://imgsrc.baidu.com/baike/pic/item/4afbfbedab64034f104872baa7c379310b551d80.jpg';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.only(top: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 這種展現圖片方式和下一種會有相同的效果
Image(image: AssetImage(_assetAli), width: 80.0, height: 80.0),
// 接下來加載圖片都會使用這些比較方便的方法
Image.asset(_assetAli, width: 80.0, height: 80.0),
// 加載一張網絡圖片
Image.network(_picUrl,
height: 80.0,
// 橫向重複
repeat: ImageRepeat.repeatX,
// MediaQuery.of(context).size 獲取到的爲上層容器的寬高
width: MediaQuery.of(context).size.width),
// 經過設置混合模式,能夠看到圖片展現的樣式已經修改
Image.asset(_assetAli,
width: 80.0, height: 80.0, color: Colors.green, colorBlendMode: BlendMode.colorDodge),
// 會優先加載指定的 asset 圖片,而後等網絡圖片讀取成功後加載網絡圖片,會經過漸隱漸現方式展示
// cover 方式按照較小的邊佈滿,較大的給切割
// contain 會按照最大的邊佈滿,較小的會被留白
// fill 會把較大的一邊壓縮
// fitHeight, fitWidth 分別按照長寬來佈滿
FadeInImage.assetNetwork(
placeholder: _assetAli, image: _picUrl, width: 120.0, height: 120.0, fit: BoxFit.cover),
// Icon 相對屬性少了不少,須要傳入一個 IconData 實例,flutter 提供了不少圖標,
// 可是實際狀況咱們須要加入咱們本身的圖標,這邊再埋坑【坑3】
// size 爲圖標顯示的大小,color 爲圖標的顏色,這邊經過 Theme 獲取主題色調
Icon(Icons.android, size: 40.0, color: Theme.of(context).primaryColorDark)
],
)),
));
}
}
複製代碼
該部分代碼查看源碼 image_main.dart
文件
最後的效果以下:
Flutter
提供了各類類型的 Button
幾乎是大同小異的,這邊就抽取一些比較經常使用的展現下效果,經常使用的主要有 RaisedButton
、FlatButton
、IconButton
、OutlineButton
、MaterialButton
、FloatActionButton
、FloatingActionButton.extended
Button
都有一個 onPress
參數,是 VoidCallback
類型的參數,經過查看源碼能夠知道 VoidCallback
是無參無返回值的一種類型參數。若是該參數傳入的值爲 null
那麼這個按鈕的就不可點擊狀態,無點擊效果,等會能夠在例子中查看。還有就是 child
參數,這裏就是傳入你須要展現的內容,好比 Text
、Icon
等等。別的參數基本能夠經過參數名瞭解,這邊不擴展了(再看源碼我怕大家都不想繼續看下去了...)
Talk is cheap, show me the code
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: const EdgeInsets.only(top: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
print('This is a Rased Button can be clicked');
},
child: Text('Raised Enable'),
),
RaisedButton(onPressed: null, child: Text('Raised Disable')),
FlatButton(
onPressed: () => print('This is a Flat Button can be clicker'),
child: Text('Flat Enable'),
),
FlatButton(onPressed: null, child: Text('Flat Disable')),
IconButton(icon: Icon(Icons.android), onPressed: () {}),
IconButton(icon: Icon(Icons.android), onPressed: null),
MaterialButton(onPressed: () {}, child: Text('Material Enable')),
MaterialButton(onPressed: null, child: Text('Material Disable')),
OutlineButton(onPressed: () {}, child: Text('Outline Enable')),
OutlineButton(onPressed: null, child: Text('Outline Enable')),
],
)),
),
floatingActionButton:
FloatingActionButton.extended(onPressed: () {}, icon: Icon(Icons.android), label: Text('Android')),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
複製代碼
該部分代碼查看源碼 button_main.dart
部分
最終的效果圖:
這篇終於到末尾了,最後留了 3 個坑等之後解決
最後代碼的地址仍是要的:
文章中涉及的代碼:demos
基於郭神 cool weather
接口的一個項目,實現 BLoC
模式,實現狀態管理:flutter_weather
一個課程(當時買了想看下代碼規範的,代碼更新會比較慢,雖然是跟着課上的一些寫代碼,可是仍是作了本身的修改,不少地方看着不舒服,而後就改爲本身的實現方式了):flutter_shop
若是對你有幫助的話,記得給個 Star,先謝過,你的承認就是支持我繼續寫下去的動力~