Flutter: Thêm Asset và ảnh

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Mục lục bài viết

Các app Flutter có thể bao gồm cả code và các asset (đôi khi được gọi là tài nguyên). Asset là một tệp được đóng gói và triển khai với ứng dụng của ta và có thể truy cập được trong thời gian chạy. Các loại nội dung phổ biến bao gồm dữ liệu tĩnh (ví dụ: tệp JSON), tệp cấu hình, biểu tượng và hình ảnh (JPEG, WebP, GIF, WebP/GIF động, PNG, BMP và WBMP).

Chỉ định asset

Flutter sử dụng file pubspec.yaml, nằm ở gốc dự án của bạn, để xác định nội dung mà ứng dụng yêu cầu.

Dưới đây là một ví dụ:

flutter:
  assets:
    - assets/my_icon.png
    - assets/background.png

Để gộp tất cả nội dung trong một thư mục, hãy chỉ định tên thư mục với ký tự / ở cuối:

flutter:
  assets:
    - directory/
    - directory/subdirectory/

Lưu ý: Chỉ các tệp nằm trực tiếp trong thư mục mới được đưa vào trừ khi có các tệp có cùng tên bên trong thư mục con (xem Biến thể Asset). Để thêm tệp nằm trong thư mục con, hãy tạo một mục entry cho mỗi thư mục.

Gói asset

Phần con assets của phần flutter chỉ định các tệp sẽ được gộp trong ứng dụng. Mỗi asset được xác định bằng một đường dẫn rõ ràng (liên quan đến file pubspec.yaml) nơi chứa tệp nội dung. Thứ tự khai báo asset không quan trọng. Tên thư mục thực tế được sử dụng (assets trong ví dụ đầu tiên hoặc directory trong ví dụ trên) không quan trọng.

Trong quá trình xây dựng, Flutter đặt nội dung vào một kho lưu trữ đặc biệt được gọi là gói asset mà các ứng dụng đọc từ đó trong thời gian chạy.

Các biến thể asset

Quá trình xây dựng hỗ trợ khái niệm về các biến thể nội dung: các phiên bản khác nhau của nội dung có thể được hiển thị trong các ngữ cảnh khác nhau. Khi đường dẫn của nội dung được chỉ định trong phần assets của pubspec.yaml, quá trình tạo sẽ tìm kiếm bất kỳ tệp nào có cùng tên trong các thư mục con liền kề. Các tệp như vậy sau đó được đưa vào gói nội dung cùng với nội dung được chỉ định.

Ví dụ: nếu bạn có các tệp sau trong thư mục ứng dụng của mình:

.../pubspec.yaml
.../graphics/my_icon.png
.../graphics/background.png
.../graphics/dark/background.png
...etc.

Và file pubspec.yaml của bạn chứa những thứ sau:

flutter:
  assets:
    - graphics/background.png

Thì cả hai graphics/background.png và graphics/dark/background.png được gộp trong gói asset của bạn. Former được coi asset chính, còn cái sau được coi là một biến thể.

Mặt khác, nếu thư mục đồ họa được chỉ định:

flutter:
  assets:
    - graphics/

Sau đó graphics/my_icon.pnggraphics/background.png và graphics/dark/background.png các tệp cũng được gộp lại.

Flutter sử dụng các biến thể nội dung khi chọn hình ảnh có độ phân giải phù hợp. Trong tương lai, cơ chế này có thể được mở rộng để gộp các biến thể cho các ngôn ngữ hoặc vùng miền khác nhau, hướng đọc, v.v.

Tải asset

Ứng dụng của bạn có thể truy cập nội dung của nó thông qua một đối tượng AssetBundle.

Hai phương pháp chính trên gói asset cho phép bạn tải nội dung chuỗi/văn bản (loadString()) hoặc nội dung hình ảnh/nhị phân (load()) ra khỏi gói, được cung cấp một khóa logic. Khóa logic ánh xạ đến đường dẫn đến nội dung được chỉ định trong pubspec.yaml tệp tại thời điểm tạo.

Tải asset văn bản

Mỗi ứng dụng Flutter có một đối tượng rootBundle để dễ dàng truy cập vào gói asset chính. Có thể tải nội dung trực tiếp bằng cách sử dụng rootBundle tĩnh toàn cục từ package:flutter/services.dart.

Tuy nhiên, nó được đề nghị để có được AssetBundle cho BuildContext hiện thời sử dụng DefaultAssetBundle, chứ không phải là gói asset mặc định đã được xây dựng với các ứng dụng; cách tiếp cận này cho phép một widget cha thay thế một widget khác AssetBundle tại thời điểm chạy, điều này có thể hữu ích cho các tình huống bản địa hóa hoặc thử nghiệm.

Thông thường, bạn sẽ sử dụng DefaultAssetBundle.of() để tải gián tiếp một nội dung, chẳng hạn như tệp JSON, từ thời gian chạy của ứng dụng rootBundle.

Bên ngoài Widget ngữ cảnh hoặc khi AssetBundle không có sẵn một chốt điều khiển, bạn có thể sử dụng rootBundle để tải trực tiếp các nội dung đó. Ví dụ:

import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;

Future<String> loadAsset() async {
  return await rootBundle.loadString('assets/config.json');
}

Tải hình ảnh

Flutter có thể tải hình ảnh có độ phân giải phù hợp với tỷ lệ pixel của thiết bị hiện tại.

Khai báo asset hình ảnh nhận biết độ phân giải

AssetImage hiểu cách ánh xạ nội dung được yêu cầu hợp lý vào một nội dung phù hợp nhất với tỷ lệ pixel thiết bị hiện tại. Để ánh xạ này hoạt động, nội dung phải được sắp xếp theo cấu trúc thư mục cụ thể:

.../image.png
.../Mx/image.png
.../Nx/image.png
...etc.

Trong đó M và N là các định danh số tương ứng với độ phân giải danh nghĩa của các hình ảnh được chứa bên trong. Nói cách khác, chúng chỉ định tỷ lệ pixel thiết bị mà hình ảnh hướng đến.

Asset chính được giả định tương ứng với độ phân giải 1.0. Ví dụ: hãy xem xét bố cục nội dung sau cho hình ảnh có tên my_icon.png:

.../my_icon.png
.../2.0x/my_icon.png
.../3.0x/my_icon.png

Trên các thiết bị có tỷ lệ pixel thiết bị là 1.8 thì asset .../2.0x/my_icon.png được chọn. Đối với tỷ lệ pixel thiết bị là 2.7 thì asset .../3.0x/my_icon.png được chọn.

Nếu chiều rộng và chiều cao của hình ảnh hiển thị không được chỉ định trên widget con Image, thì độ phân giải danh nghĩa được sử dụng để chia tỷ lệ nội dung sao cho nội dung đó chiếm cùng một lượng không gian màn hình như nội dung chính, chỉ với độ phân giải cao hơn. Nghĩa là, nếu .../my_icon.png là 72px x 72px, thì .../3.0x/my_icon.png phải là 216px x 216px; nhưng cả hai đều hiển thị thành 72px x 72px (theo pixel), nếu chiều rộng và chiều cao không được chỉ định.

Mỗi mục nhập trong phần asset của pubspec.yaml phải tương ứng với một file thực, ngoại trừ mục nhập asset chính. Nếu mục nhập asset chính không tương ứng với file thực thì nội dung có độ phân giải thấp nhất sẽ được sử dụng làm dự phòng cho các thiết bị có tỷ lệ pixel thiết bị thấp hơn độ phân giải đó. Tuy nhiên, mục nhập vẫn phải được gộp trong file manifest pubspec.yaml.

Tải hình ảnh

Để tải hình ảnh, hãy sử dụng lớp AssetImage trong phương thức build() của widget con.

Ví dụ: ứng dụng của bạn có thể tải hình nền từ các khai báo asset ở trên:

Widget build(BuildContext context) {
  return Image(image: AssetImage('graphics/background.png'));
}

Mọi thứ sử dụng gói asset mặc định đều thừa hưởng nhận thức về độ phân giải khi tải hình ảnh (nếu bạn làm việc với một số lớp cấp thấp hơn, như ImageStream hoặc ImageCache, bạn cũng sẽ nhận thấy các tham số liên quan đến tỷ lệ).

Lưu ý: Tỷ lệ pixel thiết bị phụ thuộc vào MediaQueryData.size trong đó yêu cầu phải có MaterialApp hoặc CupertinoApp làm gốc cho AssetImage của bạn.

Asset ảnh trong gói phụ thuộc

Để tải một hình ảnh từ một gói phụ thuộc thì đối số package phải được cung cấp cho AssetImage.

Ví dụ: giả sử ứng dụng của bạn phụ thuộc vào một gói được gọi my_icons, có cấu trúc thư mục sau:

.../pubspec.yaml
.../icons/heart.png
.../icons/1.5x/heart.png
.../icons/2.0x/heart.png
...etc.

Để tải hình ảnh, hãy sử dụng:

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

Các tài sản được sử dụng bởi chính gói đó cũng nên được tìm nạp bằng cách sử dụng đối số package như trên.

Nhóm các gói asset

Nếu asset mong muốn được chỉ định trong file pubspec.yaml của gói, thì asset đó sẽ tự động được đóng gói với ứng dụng. Đặc biệt, các asset được sử dụng bởi chính gói phải được ghi rõ trong pubspec.yaml của nó.

Một gói cũng có thể chọn có các asset trong thư mục lib/ của nó mà không được chỉ định trong file pubspec.yaml của nó. Trong trường hợp này, để những hình ảnh đó được đóng gói, ứng dụng phải chỉ định những hình ảnh nào sẽ được đưa vào pubspec.yaml. Ví dụ: một gói được đặt tên fancy_backgrounds có thể có các tệp sau:

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

Ví dụ, để gộp hình ảnh đầu tiên thì pubspec.yaml của ứng dụng phải chỉ định nó trong phần assets:

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

lib/ là mặc định, vì vậy nó không nên được đưa vào đường dẫn nội dung.

Chia sẻ asset với nền tảng cơ bản

Các asset Flutter có sẵn cho code sử dụng AssetManager trên Android và NSBundleiOS.

Tải asset Flutter trong Android

Trên Android, asset có sẵn thông qua API AssetManager. Ví dụ, khóa tra cứu được sử dụng trong openFd, được lấy từ lookupKeyForAsset trên PluginRegistry.Registrar hoặc getLookupKeyForAsset trên FlutterViewPluginRegistry.Registrar khả dụng khi phát triển một plugin trong khi FlutterView sẽ là lựa chọn khi phát triển một ứng dụng bao gồm cả chế độ xem nền tảng.

Ví dụ: giả sử bạn đã chỉ định những điều sau trong file pubspec.yaml của mình:

flutter:
  assets:
    - icons/heart.png

Điều này phản ánh cấu trúc sau trong ứng dụng Flutter của bạn.

.../pubspec.yaml
.../icons/heart.png
...etc.

Để truy cập icons/heart.png từ mã plugin Java của bạn, hãy làm như sau:

AssetManager assetManager = registrar.context().getAssets();
String key = registrar.lookupKeyForAsset("icons/heart.png");
AssetFileDescriptor fd = assetManager.openFd(key);

Tải asset Flutter trong iOS

Trên iOS, nội dung có sẵn thông qua mainBundle. Ví dụ pathForResource:ofType:, khóa tra cứu được sử dụng trong, được lấy từ lookupKeyForAsset hoặc lookupKeyForAsset:fromPackage: trên FlutterPluginRegistrarlookupKeyForAsset: hoặc lookupKeyForAsset:fromPackage: trên FlutterViewControllerFlutterPluginRegistrar khả dụng khi phát triển một plugin trong khi FlutterViewController sẽ là lựa chọn khi phát triển một ứng dụng bao gồm cả chế độ xem nền tảng.

Ví dụ: giả sử bạn có cài đặt Flutter từ phía trên.

Để truy cập icons/heart.png từ mã plugin Objective-C của bạn, bạn sẽ làm như sau:

NSString* key = [registrar lookupKeyForAsset:@"icons/heart.png"];
NSString* path = [[NSBundle mainBundle] pathForResource:key ofType:nil];

Để có ví dụ đầy đủ hơn, hãy xem việc triển khai video_playerplugin Flutter trên pub.dev.

Plugin ios_platform_images trên pub.dev sẽ gộp logic vào một danh mục thuận tiện. Bạn tìm nạp một hình ảnh như sau:

Objective-C:

[UIImage flutterImageWithName:@"icons/heart.png"];

Swift:

UIImage.flutterImageNamed("icons/heart.png")

Tải hình ảnh iOS trong Flutter

Khi triển khai Flutter bằng cách thêm nó vào ứng dụng iOS hiện có, bạn có thể có các hình ảnh được lưu trữ trong iOS mà bạn muốn sử dụng trong Flutter. Để thực hiện điều đó, hãy sử dụng plugin ios_platform_images có sẵn trên pub.dev.

Các asset nền tảng

Có một số trường hợp để làm việc trực tiếp với các asset trong các dự án nền tảng. Dưới đây là hai trường hợp phổ biến trong đó asset được sử dụng trước khi framework Flutter được tải và chạy.

Cập nhật biểu tượng ứng dụng

Cập nhật biểu tượng khởi chạy của ứng dụng Flutter hoạt động giống như cập nhật biểu tượng khởi chạy trong các ứng dụng Android hoặc iOS gốc.

Biểu tượng khởi chạy

Android

Trong thư mục gốc của dự án Flutter của bạn, điều hướng đến .../android/app/src/main/res. Các thư mục tài nguyên bitmap khác nhau chẳng hạn như mipmap-hdpi đã chứa các hình ảnh chỗ dành sẵn được đặt tên ic_launcher.png. Thay thế chúng bằng nội dung mong muốn của bạn theo kích thước biểu tượng được đề xuất trên mỗi mật độ màn hình như được chỉ ra trong Hướng dẫn dành cho nhà phát triển Android.

Vị trí biểu tượng Android

Lưu ý: Nếu bạn đổi tên file .png, bạn cũng phải cập nhật tên tương ứng trong thuộc tính android:icon của thẻ <application> của file AndroidManifest.xml.

iOS

Trong thư mục gốc của dự án Flutter của bạn, điều hướng đến .../ios/Runner. Thư mục Assets.xcassets/AppIcon.appiconset đã chứa hình ảnh chỗ dành sẵn (placeholder). Thay thế chúng bằng các hình ảnh có kích thước phù hợp như được chỉ ra bởi tên tệp của chúng theo quy định của Nguyên tắc giao diện người dùng của Apple. Giữ tên tệp gốc.

vị trí biểu tượng iOS

Cập nhật màn hình khởi chạy

Khởi động màn hình

Flutter cũng sử dụng các cơ chế nền tảng gốc để vẽ các màn hình khởi chạy chuyển tiếp tới ứng dụng Flutter của bạn trong khi tải framework Flutter. Màn hình khởi chạy này vẫn tồn tại cho đến khi Flutter hiển thị khung đầu tiên của ứng dụng của bạn.

Lưu ý: Điều này ngụ ý rằng nếu bạn không gọi runApp()trong phương thức main() của ứng dụng (hoặc cụ thể hơn, nếu bạn không gọi window.render()đáp lại window.onDrawFrame) thì màn hình khởi chạy sẽ tồn tại mãi mãi.

Android

Để thêm "màn hình rung lắc" vào ứng dụng Flutter của bạn, hãy điều hướng đến .../android/app/src/main. Trong res/drawable/launch_background.xml, sử dụng XML có thể vẽ danh sách lớp này để tùy chỉnh giao diện màn hình khởi chạy của bạn. Mẫu hiện có cung cấp một ví dụ về việc thêm hình ảnh vào giữa màn hình rung lắc màu trắng trong mã nhận xét. Bạn có thể bỏ ghi chú nó hoặc sử dụng drawables khác để đạt được hiệu quả mong muốn.

Để biết thêm chi tiết, hãy xem Thêm màn hình giật gân vào ứng dụng di động của bạn.

iOS

Để thêm hình ảnh vào giữa "màn hình giật gân", hãy điều hướng đến .../ios/Runner. Trong Assets.xcassets/LaunchImage.imageset, thả trong hình ảnh được đặt tên LaunchImage.pngLaunchImage@2x.pngLaunchImage@3x.png. Nếu bạn sử dụng các tên tệp khác nhau, hãy cập nhật file Contents.json trong cùng một thư mục.

Bạn cũng có thể tùy chỉnh hoàn toàn bảng phân cảnh màn hình khởi chạy của mình trong Xcode bằng cách mở .../ios/Runner.xcworkspace. Điều hướng đến Runner/Runner trong Project Navigator và thả vào các hình ảnh bằng cách mở Assets.xcassets hoặc thực hiện bất kỳ tùy chỉnh nào bằng cách sử dụng Interface Builder trong LaunchScreen.storyboard.

Thêm biểu tượng khởi chạy trong Xcode

Để biết thêm chi tiết, hãy xem Thêm màn hình rung lắc vào ứng dụng di động của bạn.

Nguồn: flutter.dev
» Tiếp: Tìm hiểu hệ thống điều hướng và định tuyến mới của Flutter
« Trước: Thêm tương tác vào ứng dụng Flutter
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!