Widget介紹
widget可以把它看作成一個元件(或者是一個單元),在Flutter中,就是通過widget來建構項目的UI,Flutter有一套豐富、強大的基礎widget,下面是比較常用的Widget
runApp函數
接受給定的Widget并使用其作為widget根
Stateless widgets
是不可變的,這意味着它們的屬性不能改變——所有的值都是 final
Stateful widgets
持有的狀态可能在 widget 生命周期中發生變化,實作一個 stateful widget 至少需要兩個類:
- 一個 StatefulWidget 類;
- 一個 State 類;
StatefulWidget 類本身是不變的,但是 State 類在widget 生命周期中始終存在,通過State裡面修改屬性的值進而達到頁面的重新渲染;
如果需要變化需要重新建立。StatefulWidget可以儲存自己的狀态。那問題是既然widget都是immutable的,怎麼儲存狀态?其實Flutter是通過引入了State來儲存狀态。當State的狀态改變時,
能重新建構本節點以及孩子的Widget樹來進行UI變化。注意:如果需要主動改變State的狀态,需要通過setState()方法進行觸發,單純改變資料是不會引發UI改變的
内容widget
Text 文本
該 widget 可讓建立一個帶格式的文本
示例demo1 (直接new Text的方式來設定)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: new Text(
// 顯示文本
"Hello world",
// 對齊方式
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
// 設定樣式
style: TextStyle(color:Colors.pink)
),
);
}
}
示例demo2 (通過 Text.rich)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Text.rich(
TextSpan(
// 預設文本
text: 'Hello',
style: TextStyle(fontSize: 20),//設定預設的大小
children: <TextSpan>[//裡面可以放多個文本TextSpan,可以單獨給每一個文本進行樣式的設定和内容的設定
TextSpan(text:'第一個顯示的文本',style:TextStyle(fontSize: 24,fontWeight: FontWeight.bold)),
TextSpan(text:'第二個顯示的文本',style:TextStyle(fontWeight: FontWeight.bold,fontStyle: FontStyle.italic))
]
)
)
);
}
}
Text元件常用屬性詳解
Text(this.data, {
Key key,
this.style,
this.textAlign,//文本方向(左(TextAlign.left)|右(TextAlign.right)|中(TextAlign.center)|兩端對齊(TextAlign.justify)|開始(TextAlign.start)|結束(TextAlign.end))
this.textDirection,//文本對齊方式(文本從右到左(TextDirection.rtl)|文本從左到右(TextDirection.ltr))
this.locale,
this.softWrap,//文本是否能換行
this.overflow,//文本溢出的處理方式(剪切(TextOverflow.clip)|隐藏(TextOverflow.fade)|省略号(TextOverflow.ellipsis))
this.textScaleFactor,//文本字型縮放倍數
this.maxLines,//文本最多能顯示多少行
this.semanticsLabel,
}) : assert(data != null),
textSpan = null,
super(key: key);
TextStyle 常用屬性詳解
源碼中 style及構造函數
const TextStyle({
this.inherit = true,//是否将null值替換為祖先文本樣式中的值(例如,在TextSpan樹中)。如果為false,則沒有顯式值的屬性将恢複為預設值:白色,字型大小為10像素,采用無襯線字型
this.color,//文本顔色
this.backgroundColor,//背景顔色
this.fontSize,//文字大小
this.fontWeight,// 是否加粗,利用FontWeight 來設定
this.fontStyle,// 字型風格,利用FontStyle 來設定
this.letterSpacing,//字母間距,整數拉開字母距離,若是負數則拉近字母距離
this.wordSpacing,//單詞間距,同上
this.textBaseline,//用于對齊文本的水準線
this.height,//文本行高,為字型大小的倍數
this.locale,//文本國際化
this.foreground,//字型前景
this.background,//文本背景
this.shadows,// 文本的陰影可以利用清單疊加處理,例如shadows: [Shadow(color:Colors.black,offset: Offset(6, 3), blurRadius: 10)], color即陰影的顔色, offset即陰影相對文本的偏移坐标,blurRadius即陰影的模糊程度,越小越清晰
this.fontFeatures,
this.decoration,//文字的線性裝飾,比如 underline 下劃線, lineThrough删除線
this.decorationColor,//文本裝飾線的顔色
this.decorationStyle,//文本裝飾線的樣式,比如 dashed 虛線
this.decorationThickness,
this.debugLabel,//這種文本樣式的可讀描述,此屬性僅在調試建構中維護
String fontFamily,
List<String> fontFamilyFallback,
String package,
}) : fontFamily = package == null ? fontFamily : 'packages/$package/$fontFamily',
_fontFamilyFallback = fontFamilyFallback,
_package = package,
assert(inherit != null),
assert(color == null || foreground == null, _kColorForegroundWarning),
assert(backgroundColor == null || background == null, _kColorBackgroundWarning);
Image 圖檔
如果要顯示圖檔,則需要使用 Image 控件,支援 JPEG、PNG、GIF、Animated GIF、WebP、Animated WebP、BMP 和 WBMP 等格式。Image 可以顯示檔案、資源包或者網絡圖檔,當圖
标加載完後會在 界面顯示;圖檔具有寬度、高度、顔色過濾器(類似于 Android 中的 tint color)、fit 模式、重複模式 等屬性。 和 Android 中 ImageView 的屬性差不多
加載網絡圖檔
- 在頁面通過 Image.network 來進行引用
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.white,
),
// 通過 network 來進行網絡圖檔的引入
home: Image.network('http://www.itcast.cn/2018czgw/images/logo.png')
);
}
}
加載資源圖檔
加載的是項目中資源目錄的檔案
- 在項目根目錄建立assets檔案夾,在裡面建立images檔案夾,裡面放入資源圖檔
- 在
檔案中配置資源目錄pubspec.yaml
flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/images/1.png
- 在頁面 通過 Image.asset 來進行引入
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.white,
),
// 通過asset 來進行資源圖檔的引入
home: new Image.asset('assets/images/logo.png')
);
}
}
加載本地圖檔
加載的是手機的本地存儲的圖檔
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;//Android來說 /data/user/0/com.example.fluttersample/cache
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;//Android來說 /data/user/0/com.example.fluttersample/app_flutter
String storageDir = (await getExternalStorageDirectory()).path;//Android來說 /storage/emulated/0/ sd卡的路徑
- 操作SD卡需要申請相應的權限,在
檔案中添加如下AndroidManifest.xml
<!-- 寫權限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 讀權限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- 編寫代碼,這裡擷取sd卡目錄是異步的,我們需要通過,async和await來配合使用,在方法中擷取到路徑之後,通過setState來更新頁面
- 這裡需要更新資料,我們需要建立一個類 繼承 StateFulWidget
- 在createState方法中傳回 ImageState
- 建立ImageState 繼承 State
- 在bulde方法中調用擷取SD卡路徑的方法
- 在build return 裡面調用 Image.file() 來引入本地檔案
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.white,
),
home: new ImageWidget());
}
}
class ImageWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new ImageState();
}
}
class ImageState extends State<ImageWidget> {
String _storageStr = '';
@override
Widget build(BuildContext context) {
// 判斷如果為空,那麼調用擷取sd卡路徑的方法
if(_storageStr=='') _getLocalFile();
print(_storageStr);
// TODO: implement build
// 通過加載 本地檔案的方式來 引入圖檔,如果要設定屬性,接着寫在後面就好,詳細的屬性在後面有講解
return new Image.file(new File('$_storageStr/Pictures/logo.png',color:Colors.pink));
}
/**
* 封裝方法,擷取sd卡路徑是異步方法
*/
_getLocalFile() async {
String storageDir = (await getExternalStorageDirectory()).path;
// 擷取到了之後,通過 setState方式來更新頁面資料,注意,setSate 隻能在 state裡面進行調用
setState(() {
this._storageStr = storageDir;
});
}
}
記憶體中加載圖檔
用于從記憶體裡(Uint8List)顯示圖檔
// Uint8List圖檔
new Image.memory(bytes),
圖檔的其他參數
屬性名 | 說明 |
---|---|
semanticLabel | 圖像的語義描述 |
excludeFromSemantics | 預設false 是否啟用圖像的語義描述 |
width | 寬度 一般結合 ClipOval 才能看到效果 |
height | 高度 一般結合 ClipOval 才能看到效果 |
color | 背景色 |
colorBlendMode | 使圖像與背景色混合 模式 |
fit | BoxFit.fill:全圖顯示,圖檔會被拉伸,并充滿父容器。 BoxFit.contain:全圖顯示,顯示原比例,可能會有空隙。 BoxFit.cover:顯示可能拉伸,可能裁切,充滿(充滿容器不變形)。 BoxFit.fitWidth:寬度充滿(橫向充滿),顯示可能拉伸,可能裁切。 BoxFit.fitHeight :高度充滿(豎向充滿),顯示可能拉伸,可能裁切。 BoxFit.scaleDown:效果和 contain 差不多,但是此屬性不允許顯示超過源圖檔大小,可小不可大 |
alignment | 對齊方式 |
repeat | 平鋪 ImageRepeat.repeat : 橫向和縱向都進行重複,直到鋪滿整個畫布 ImageRepeat.repeatX: 橫向重複,縱向不重複。 ImageRepeat.repeatY:縱向重複,橫向不重複。 |
centerSlice | 設定拉伸部位,不能和fit一同使用 圖檔大于等于容器時 屬性無效 |
matchTextDirection | 預設false 官方翻譯:是否在TextDirection的方向上繪制圖像 |
gaplessPlayback | 預設false 官方翻譯:當圖像提供者發生變化時,是繼續顯示舊圖像,預設不顯示 |
filterQuality | 預設FilterQuality.low 官方翻譯:圖像過濾器的品質級别。(渲染模式的品質) |