Flutter 知識(shí)梳理 (資源加載) - Flutter APK 文件、圖片、字體的加載

在開(kāi)發(fā)Flutter APK時(shí),我們可以將一些資源預(yù)置在APP中,這些資源可以分為以下幾類:

  • 文本
  • 圖片

為了統(tǒng)一管理,我們將它們統(tǒng)一放在assets/目錄下,然后介紹一下如何對(duì)它們進(jìn)行讀取。

image.png

一、文本

文本一般用于存儲(chǔ)默認(rèn)數(shù)據(jù),在第一次進(jìn)入無(wú)網(wǎng)的情況下進(jìn)行數(shù)據(jù)的展示。

pubspec.yamlflutter標(biāo)簽下,聲明要加載的文件名:

flutter:

  assets :
    - assets/files/hello.txt

文本的加載有兩種方式:

  • 使用全局的靜態(tài)rootBundle對(duì)象,需要導(dǎo)入package:flutter/services.dart,好處是不需要提供BuildContext。
  • 使用DefaultAssetBundle獲取當(dāng)前BuildContextAssetBundle來(lái)加載。

兩種方式的示例代碼如下,分別對(duì)應(yīng)于_loadAssetFile()_loadAssetFile2()

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(AssetDemo());

class AssetDemo extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Assets Demo')),
        body: AssetFilesWidget(),
      ),
    );
  }

}

class AssetFilesWidget extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    return _AssetFilesWidgetState();
  }

}

class _AssetFilesWidgetState extends State<AssetFilesWidget> {

  String text;

  @override
  void initState() {
    super.initState();
    _loadAssetFile2();
  }

  @override
  Widget build(BuildContext context) {
    return Text(text ?? 'default');
  }

  _loadAssetFile() async {
    String text = await rootBundle.loadString('assets/files/hello.txt');
    print(text);
    setState(() {
      this.text = text;
    });
  }

  _loadAssetFile2() async {
    String text = await DefaultAssetBundle.of(context).loadString('assets/files/hello.txt');
    setState(() {
      this.text = text;
    });
  }

}

二、圖片

圖片的加載和文本類似,也是需要先進(jìn)行聲明再使用。

Android中,我們會(huì)將圖片放在res/下對(duì)應(yīng)的drawable-?文件夾中,而放在不同的文件夾中,根據(jù)設(shè)備dpi(每英寸圖片上點(diǎn)的個(gè)數(shù))的不同,最終加載到內(nèi)存中的圖片大小是不一樣的,在Flutter中也有類似的概念。

關(guān)于Android中相關(guān)的概念可以查看這篇文章 圖片基礎(chǔ)知識(shí)梳理(2) - Bitmap 占用內(nèi)存分析。

Android 下的目錄

Flutter中,也有和drawable-?相同的設(shè)計(jì),用N.X來(lái)代替:

其加載的邏輯為:

  • 根目錄默認(rèn)對(duì)應(yīng)于1.0分辨率的圖片。
  • 設(shè)備在選擇圖片時(shí),將會(huì)選擇離它dpiDensity最近的文件夾。假如dpiDensity=1.8,那么會(huì)選擇2.0x目錄下的資源。(dpiDensityMediaQuery.of(context).devicePixelRatio來(lái)獲取。)
  • 確定了需要選擇哪個(gè)文件夾的圖片后,假如沒(méi)有設(shè)置Image Widget控件的大小,那么最終加載顯示的寬高還要用原始圖片寬高再除以對(duì)應(yīng)文件夾的系數(shù)。

示例如下:
pubspec.yaml中聲明:

flutter:

  uses-material-design: true

  assets :
    - assets/files/hello.txt
    - assets/images/

使用Image(key : imageKey, image : AssetImage('assets/images/pic.png'))加載圖片。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(AssetDemo());

class AssetDemo extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Assets Demo')),
        body: AssetImageWidget(),
      ),
    );
  }

}

class AssetImageWidget extends StatefulWidget {
  
  @override
  State<StatefulWidget> createState() {
    return _AssetImageWidgetState();
  }
  
}

class _AssetImageWidgetState extends State<AssetImageWidget> {
  
  String text;
  GlobalKey imageKey = new GlobalKey();
  
  @override
  Widget build(BuildContext context) {
    return Column(children: <Widget>[
      RaisedButton(onPressed: () {
        text = 'height=${imageKey.currentContext.size.height}'
            ',width=${imageKey.currentContext.size.height}'
            ',dpi=${MediaQuery.of(context).devicePixelRatio}';
        print(text);
      }, child: Text('refresh')),
      Image(key : imageKey, image : AssetImage('assets/images/pic.png'))
    ]);
  }
}

為了驗(yàn)證之前的加載邏輯,試驗(yàn)了以下三種情況:

  • 在主資源assets/images目錄下添加pic.png,結(jié)果為:
height=96.0,width=96.0,dpi=3.0
  • 在主資源和assets/images/3.0x目錄下添加pic.png,結(jié)果為:
height=32.0,width=32.0,dpi=3.0
  • 在主資源和assets/images/2.0x目錄下添加pic.png,結(jié)果為:
height=48.0,width=48.0,dpi=3.0

這里有點(diǎn)需要注意,當(dāng)我們改變資源目錄的結(jié)構(gòu)時(shí),需要修改pubspec.yaml才能生效。

三、使用第三方包中的圖片

3.1 應(yīng)用程序使用第三方包中的圖片

當(dāng)應(yīng)用程序依賴于包名為my_icons的包,加載圖像的方式為:

AssetImage('icons/heart.png', package: 'my_icons')

3.2 打包第三方圖片

對(duì)于第三方包中的圖片,有以下幾種情況:

  • 第三方包自己使用的資源,那么必須要在它自身的pubspec.yaml中聲明,并且使用的時(shí)候要帶上自己的包名。
  • 第三方包提供給其它人使用,但自身不使用,分為兩種情況:
    • 無(wú)論使用者是否用到都強(qiáng)制打包。這種情況下,第三方包需要在它的pubspec.yaml中聲明,使用者則不需要。
    • 由使用者選擇是否打包。第三方包將資源放在lib/目錄下并且不在pubspec.yaml中聲明,由使用者根據(jù)使用情況在它自己的pubspec.yaml中聲明。

例如第三方包名為fancy_backgrounds,它的資源有:

…/lib/backgrounds/background1.png
…/lib/backgrounds/background2.png
…/lib/backgrounds/background3.png

假如使用者希望使用background1,那么就要在它自己的pubspec.yaml中聲明,注意這里省略了隱式的lib目錄:

flutter:
  assets:
    - packages/fancy_backgrounds/backgrounds/background1.png

參考文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容