## 圖片及ICON
### 圖片
Flutter中,我們可以通過Image來加載并顯示圖片,Image的數據源可以是asset、文件、內存以及網絡。
### ImageProvider
`ImageProvider` 是一個抽象類,主要定義了圖片數據獲取的接口`load()`,從不同的數據源獲取圖片需要實現不同的`ImageProvider` ,如`AssetImage`是實現了從Asset中加載圖片的ImageProvider,而`NetworkImage`實現了從網絡加載圖片的ImageProvider。
### Image
`Image` widget有一個必選的`image`參數,它對應一個ImageProvider。下面我們分別演示一下如何從asset和網絡加載圖片。
#### 從asset中加載圖片
1. 在工程根目錄下創建一個`images目錄`,并將圖片avatar.png拷貝到該目錄。
2. 在`pubspec.yml`中的`flutter`部分添加如下內容:
```
assets:
- images/avatar.png
```
3. 加載該圖片
```
Image(
image: AssetImage("images/avatar.png"),
width: 100.0
);
```
Image也提供了一個快捷的構造函數`Image.asset`用于從asset中加載、顯示圖片:
```
Image.asset("images/avatar.png",
width: 100.0,
)
```
#### 從網絡加載圖片
```
Image(
image: NetworkImage(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
width: 100.0,
)
```
Image也提供了一個快捷的構造函數`Image.network`用于從網絡加載、顯示圖片:
```
Image.network(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
width: 100.0,
)
```
運行上面兩個示例,圖片加載成功后顯示如下:

#### 參數
`Image`在顯示圖片時定義了一系列參數,通過這些參數我們可以控制圖片的顯示外觀、大小、混合效果等。我們看一下Image的主要參數:
```
const Image({
...
this.width, //圖片的寬
this.height, //圖片高度
this.color, //圖片的混合色值
this.colorBlendMode, //混合模式
this.fit,//縮放模式
this.alignment = Alignment.center, //對齊方式
this.repeat = ImageRepeat.noRepeat, //重復方式
...
})
```
- `width`、`height`:用于設置圖片的寬、高,當不指定寬高時,圖片會根據當前父容器的限制,盡可能的顯示其原始大小,如果只設置`width`、`height`的其中一個,那么另一個屬性默認會按比例縮放,但可以通過下面介紹的`fit`屬性來指定適應規則。
- `fit`:該屬性用于在圖片的顯示空間和圖片本身大小不同時指定圖片的適應模式。適應模式是在`BoxFit`中定義,它是一個枚舉類型,有如下值:
- `fill`:會拉伸填充滿顯示空間,圖片本身長寬比會發生變化,圖片會變形。
- `cover`:會按圖片的長寬比放大后居中填滿顯示空間,圖片不會變形,超出顯示空間部分會被剪裁。
- `contain`:這是圖片的默認適應規則,圖片會在保證圖片本身長寬比不變的情況下縮放以適應當前顯示空間,圖片不會變形。
- `fitWidth`:圖片的寬度會縮放到顯示空間的寬度,高度會按比例縮放,然后居中顯示,圖片不會變形,超出顯示空間部分會被剪裁。
- `fitHeight`:圖片的高度會縮放到顯示空間的高度,寬度會按比例縮放,然后居中顯示,圖片不會變形,超出顯示空間部分會被剪裁。
- `none`:圖片沒有適應策略,會在顯示空間內顯示圖片,如果圖片比顯示空間大,則顯示空間只會顯示圖片中間部分。
一圖勝萬言:

- `color`和 `colorBlendMode`:在圖片繪制時可以對每一個像素進行顏色混合處理,`color`指定混合色,而`colorBlendMode`指定混合模式,下面是一個簡單的示例:
```
Image(
image: AssetImage("images/avatar.png"),
width: 100.0,
color: Colors.blue,
colorBlendMode: BlendMode.difference,
);
```
運行效果如下(彩色):

- `repeat`:當圖片本身大小小于顯示空間時,指定圖片的重復規則。簡單示例如下:
```
Image(
image: AssetImage("images/avatar.png"),
width: 100.0,
height: 200.0,
repeat: ImageRepeat.repeatY ,
)
```
運行后效果如下:

### ICON
Flutter中,可以像web開發一樣使用iconfont,iconfont即“字體圖標”,它是將圖標做成字體文件,然后通過指定不同的字符而顯示不同的圖片。
> 在字體文件中,每一個字符都對應一個位碼,而每一個位碼對應一個顯示字形,不同的字體就是指字形不同,即字符對應的字形是不同的。而在iconfont中,只是將位碼對應的字形做成了圖標,所以不同的字符最終就會渲染成不同的圖標。
在Flutter開發中,iconfont和圖片相比有如下優勢:
1. 體積小:可以減小安裝包大小。
2. 矢量的:iconfont都是矢量圖標,放大不會影響其清晰度。
3. 可以應用文本樣式:可以像文本一樣改變字體圖標的顏色、大小對齊等。
4. 可以通過TextSpan和文本混用。
##### 使用Material Design字體圖標
Flutter默認包含了一套Material Design的字體圖標,在`pubspec.yaml`文件中的配置如下
```
flutter:
uses-material-design: true
```
Material Design所有圖標可以在其官網查看:<https://material.io/tools/icons/>
我們看一個簡單的例子:
```
String icons = "";
// accessible: ? or 0xE914 or E914
icons += "\uE914";
// error: or 0xE000 or E000
icons += " \uE000";
// fingerprint: ? or 0xE90D or E90D
icons += " \uE90D";
Text(icons,
style: TextStyle(
fontFamily: "MaterialIcons",
fontSize: 24.0,
color: Colors.green
),
);
```
運行效果如下:

通過這個示例可以看到,使用圖標就像使用文本一樣,但是這種方式需要我們提供每個圖標的碼點,這并對開發者不友好,所以,Flutter封裝了一個`IconData`和`Icon`來專門顯示字體圖標,上面的例子也可以用如下方式實現:
```
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.accessible,color: Colors.green,),
Icon(Icons.error,color: Colors.green,),
Icon(Icons.fingerprint,color: Colors.green,),
],
)
```
`Icons`類中包含了所有Material Design圖標的`IconData`靜態變量定義。
#### 使用自定義字體圖標
我們也可以使用自定義字體圖標。iconfont.cn上有很多字體圖標素材,我們可以選擇自己需要的圖標打包下載后,會生成一些不同格式的字體文件,在Flutter中,我們使用ttf格式即可。
假設我們項目中需要使用一個書籍圖標和微信圖標,我們打包下載后導入:
1. 導入字體圖標文件;這一步和導入字體文件相同,假設我們的字體圖標文件保存在項目根目錄下,路徑為"fonts/iconfont.ttf":
```
fonts:
- family: myIcon #指定一個字體名
fonts:
- asset: fonts/iconfont.ttf
```
2. 為了使用方便,我們定義一個`MyIcons`類,功能和`Icons`類一樣:將字體文件中的所有圖標都定義成靜態變量:
```
class MyIcons{
// book 圖標
static const IconData book = const IconData(
0xe614,
fontFamily: 'myIcon',
matchTextDirection: true
);
// 微信圖標
static const IconData wechat = const IconData(
0xec7d,
fontFamily: 'myIcon',
matchTextDirection: true
);
}
```
3. 使用
```
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MyIcons.book,color: Colors.purple,),
Icon(MyIcons.wechat,color: Colors.green,),
],
)
```
運行后效果如下:

- 緣起
- 起步
- 移動開發技術簡介
- Flutter簡介
- 搭建Flutter開發環境
- 常見配置問題
- Dart語言簡介
- 第一個Flutter應用
- 計數器示例
- 路由管理
- 包管理
- 資源管理
- 調試Flutter APP
- Dart線程模型及異常捕獲
- 基礎Widgets
- Widget簡介
- 文本、字體樣式
- 按鈕
- 圖片和Icon
- 單選框和復選框
- 輸入框和表單
- 布局類Widgets
- 布局類Widgets簡介
- 線性布局Row、Column
- 彈性布局Flex
- 流式布局Wrap、Flow
- 層疊布局Stack、Positioned
- 容器類Widgets
- Padding
- 布局限制類容器ConstrainedBox、SizeBox
- 裝飾容器DecoratedBox
- 變換Transform
- Container容器
- Scaffold、TabBar、底部導航
- 可滾動Widgets
- 可滾動Widgets簡介
- SingleChildScrollView
- ListView
- GridView
- CustomScrollView
- 滾動監聽及控制ScrollController
- 功能型Widgets
- 導航返回攔截-WillPopScope
- 數據共享-InheritedWidget
- 主題-Theme
- 事件處理與通知
- 原始指針事件處理
- 手勢識別
- 全局事件總線
- 通知Notification
- 動畫
- Flutter動畫簡介
- 動畫結構
- 自定義路由過渡動畫
- Hero動畫
- 交錯動畫
- 自定義Widget
- 自定義Widget方法簡介
- 通過組合現有Widget實現
- 實例:TurnBox
- CustomPaint與Canvas
- 實例:圓形漸變進度條(自繪)
- 文件操作與網絡請求
- 文件操作
- Http請求-HttpClient
- Http請求-Dio package
- 實例:Http分塊下載
- WebSocket
- 使用Socket API
- Json轉Model
- 包與插件
- 開發package
- 插件開發:平臺通道簡介
- 插件開發:實現Android端API
- 插件開發:實現IOS端API
- 系統能力調用
- 國際化
- 讓App支持多語言
- 實現Localizations
- 使用Intl包
- Flutter核心原理
- Flutter UI系統
- Element和BuildContext
- RenderObject與RenderBox
- Flutter從啟動到顯示