, October 26, 2021

0 kết quả được tìm thấy

Sử dụng assets trong Flutter package? Tại sao không?

  • Đăng bởi  Kieu Hoa
  •  Aug 28, 2021

  •   10 min reads
Sử dụng assets trong Flutter package? Tại sao không?

Nếu bạn truy cập vào bài viết này để tìm hiểu cách đưa hình ảnh, phông chữ hoặc các asset khác vào ứng dụng Flutter của mình, thì có thể bạn đã nhầm chỗ. Đùa thôi bạn có thể xem video ở bên dưới nhé! Còn bài viết này mình sẽ hướng dẫn các bạn sử dụng asset trong package (thư viện) của người ta.

1. Bạn nên đặt các asset ở đâu?

Bạn có một hình ảnh, phông chữ hoặc thứ gì đó muốn cung cấp cho các lập trình viên khác sử dụng khi họ dùng package của bạn. Vậy câu hỏi đặt ra là bạn nên đặt nó ở đâu?

Bạn có thể đặt nó vào trong thư mục lib/. Bình thường bạn hay tạo folder assets ở ngoài root project đúng không? Nhưng khi bạn tạo package cho người khác sử dụng thì bạn nên bỏ các assets vào folder lib luôn để họ dễ theo dõi.

Mọi thứ trong thư mục lib/ sẽ được tự động đóng gói với ứng dụng. Những asset đó sẽ có sẵn cho bất kỳ ai sử dụng package của bạn. Với một package developer, bạn thậm chí không cần phải khai báo những asset đó trong pubspec.yaml nếu bạn không sử dụng. Chúng vẫn được đóng gói cùng với package.

Sự lựa chọn khác là tạo một thư mục mới trong dự án chính. Gọi nó là assets  hoặc fonts hoặc bất cứ điều gì bạn muốn.

Assets trong thư mục dự án chính

Tuy nhiên, bất kỳ asset nào không có trong thư mục lib/ sẽ không được thêm vào assets bundle của package trừ khi bạn khai báo chúng trong file pubspec.yaml:

flutter:
  assets:
    - assets/my_image.jpg
  fonts:
    - family: MyFontFamily
      fonts:
        - asset: assets/my_font.ttf

Bạn có thể xem một số ví dụ để có thể hiểu cách hoạt động của điều này. Tôi sẽ chỉ cho bạn bốn package Flutter khác nhau trên Pub.dev mà mỗi package thực hiện hơi khác một chút. Bạn sẽ thấy cách mà assets được sử dụng như thế nào từ cả quan điểm của tác giả và người dùng package đó.

2. Ví dụ 1: shrine_images

Package shrine_images không thực sự hữu ích ngoài việc cung cấp image assets cho ứng dụng Shrine, một phần của ứng dụng demo Flutter Gallery . Nhưng nó hữu ích khi chỉ ra cách đưa assets vào package Flutter và có lẽ đó là mục đích chính của nó.

Package developer đặt tất cả các asset trong thư mục lib/ như sau:

shrine_images/lib/
  2.0x/
    0-0.jpg
    1-0.jpg
    10-0.jpg
    ...
  3.0x/
    0-0.jpg
    1-0.jpg
    10-0.jpg
    ...
  0-0.jpg
  1-0.jpg
  10-0.jpg
  ...

Ba density versions khác nhau của mỗi hình ảnh tồn tại. Không có gì khác trong thư mục lib/ ngoại trừ những hình ảnh này. Nếu bạn nhìn vào tệp pubspec.yaml, không có bất kỳ asset nào được đề cập đến. Chỉ cần đưa chúng vào thư mục lib/ là đủ.

2.1 Các developer sử dụng asset trong package như thế nào

Hơi khó để theo cách ứng dụng Shrine sử dụng package, vì vậy, tôi sẽ tạo một ứng dụng đơn giản sử dụng package shrine_images. Khai báo package đó trong file pubspec.yaml như sau:

name: flutter_assets
description: A Flutter app.

version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  shrine_images: ^1.1.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
  assets:
    - packages/shrine_images/10-0.jpg

Lưu ý hai điều:

  1. Tôi đã thêm shrine_images: ^1.1.2 như một dependency.
  2. Tôi đã thêm — packages/shrine_images/10–0.jpg dưới flutter assets. Bạn bắt đầu với package/. Sau đó, bạn cho biết tên package (trong trường hợp này là shrine_images). Sau đó, bạn cung cấp vị trí và tên tệp trong thư mục lib/. Bạn không thêm lib bởi vì điều đó được giả định. Tôi chỉ sử dụng một hình ảnh trong ứng dụng đơn giản của mình. Nếu tôi sử dụng nhiều hình ảnh hơn, tôi sẽ phải liệt kê chúng riêng lẻ (giống như ứng dụng Shrine). Bạn không thể chỉ định thư mục giống như với local assets.

File main.dart của tôi trông giống như sau:‌

 import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('My App')),
        body: Center(
          child: Image(
            image: AssetImage(
              '10-0.jpg',
              package: 'shrine_images',
            ),
          ),
        ),
      ),
    );
  }
}

Lưu ý rằng bạn không cần phải khai báo thư viện shrine_images ở đầu file.‌‌Để có được hình ảnh, bạn sử dụng AssetImage và cung cấp cho nó tên asset và tên package. Dưới đây là code minh hoạ.

AssetImage('10-0.jpg', package: 'shrine_images')

Bạn chạy ứng dụng thì sẽ thấy như thế này

Một ứng dụng sử dụng package shrine_images

3. Ví dụ 2: font_awesome_flutter

Package font_awesome_flutter cung cấp một bộ phông chữ với rất nhiều icon hữu ích. Các phông chữ được đóng gói sẵn trong package.

Package này đặt các font asset trong một thư mục con của lib/ như thế này:

font_awesome_flutter/lib/
  font/
    fa-brands-400.ttf
    fa-regular-400.ttf
    fa-solid-900.ttf
  font_awesome_flutter.dart
  icon_data.dart

Tuy nhiên, vì lập trình viên đang sử dụng các asset trong logic package, họ cũng khai báo các phông chữ dưới dạng asset trong tệp pubspec.yaml:

flutter:
  fonts:
    - family: FontAwesomeBrands
      fonts:
        - asset: lib/fonts/fa-brands-400.ttf
          weight: 400
    - family: FontAwesomeRegular
      fonts:
        - asset: lib/fonts/fa-regular-400.ttf
          weight: 400
    - family: FontAwesomeSolid
      fonts:
        - asset: lib/fonts/fa-solid-900.ttf
          weight: 900

Và đây là một đoạn code của nó được sử dụng trong file icon_data.dart:‌

class IconDataBrands extends IconData {
  const IconDataBrands(int codePoint)
      : super(
          codePoint,
          fontFamily: 'FontAwesomeBrands',
          fontPackage: 'font_awesome_flutter',
        );
}

Package đã làm sẵn điều này giúp người dùng package cảm thấy dễ dàng hơn rất nhiều khi sử dụng.

3.1 Các developer sử dụng asset trong package như thế nào

Lập trình viên ứng dụng chỉ cần thêm font_awesome_flutter  vào file pubspec.yaml của ứng dụng.

dependencies:
  font_awesome_flutter: ^8.5.0

Không cần phải khai báo bất kỳ font asset nào. Lập trình viên ứng dụng thậm chí không cần biết tên của các tệp phông chữ.

Bạn chỉ cần import package và sử dụng trực tiếp. Đây là file main.dart cho một bản demo đơn giản:

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('My App')),
        body: Center(
          child: IconButton(
            icon: Icon(FontAwesomeIcons.wordpress),
            iconSize: 100,
            onPressed: (){},
          ),
        ),
      ),
    );
  }
}

Bạn chỉ cần truyền dữ liệu FontAwesomeIcons.wordpress vào một Icon widget. Điều này giúp cho công việc của lập trình viên ứng dụng trở nên cực kỳ dễ dàng. Chạy ứng dụng ngay bây giờ, bạn sẽ thấy:

Một ứng dụng sử dụng package font_awesome_flutter

4. Ví dụ 3: crypto_font_icons

Package crypto_font_icons tương tự như font_awesome_flutter ở chỗ nó cung cấp một phông chữ tùy chỉnh cho các lập trình viên ứng dụng sử dụng. Lý do tôi đề cập đến nó là package developer đã sử dụng một cấu trúc thư mục khác.

Thay vì đặt font vào thư mục lib/, package developer đã tạo một thư mục fonts trong thư mục package chính như thế này:

cryptofont-flutter/
  font/
    cryptofont-webfont.ttf
  lib/
    crypto_font_icon_data.dart
    crypto_font_icons.dart

Sau đó, pubspec.yaml trông như thế này:

flutter:
  fonts:
    - family: CryptoFont
      fonts:
        - asset: font/cryptofont-webfont.ttf

Bằng cách liệt kê phông chữ dưới dạng asset trong pubspec.yaml, nó vẫn được đưa vào gói asset và do đó sẽ có sẵn cho các lập trình viên ứng dụng sử dụng package này.

4.1 Các developer sử dụng asset trong package như thế nào

Từ quan điểm của lập trình viên ứng dụng, không có vấn đề gì khi package developer không đặt asset vào thư mục lib/. Đó là tất cả những gì được package giấu đi. Chỉ cần phụ thuộc vào nó

dependencies:
  crypto_font_icons: ^0.1.0+1

Và sử dụng nó giống như chúng ta đã làm trong ví dụ font_awesome_flutter ở trên.

import 'package:crypto_font_icons/crypto_font_icons.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('My App')),
        body: Center(
          child: IconButton(
            icon: Icon(CryptoFontIcons.BTC),
            iconSize: 100,
            onPressed: (){},
          ),
        ),
      ),
    );
  }
}

Điều này cho ra:

5. Ví dụ  4: mongol

Trong phiên bản gốc của bài viết này, tôi chỉ có ba ví dụ. Trình bày những ví dụ này giúp tôi học cách tự làm điều đó. Tuy nhiên, tôi đã phát hiện ra khi làm việc trên package rằng các ví dụ trên không đề cập đến cách cung cấp phông chữ. Ví dụ 1 sử dụng widget AssetImage để chỉ định package và ví dụ 2 và 3 sử dụng widget IconData để chỉ định package. Nhưng tôi muốn chia sẻ toàn bộ một phông chữ.

Package của tôi được gọi là mongol. Bạn sẽ không bao giờ sử dụng nó trừ khi bạn là một trong số ít lập trình viên Flutter tạo ứng dụng cho vertical Mongolian text. Tuy nhiên, vì source code nằm trên GitHub, bạn có thể thấy cách tôi cung cấp tệp phông chữ (không chỉ icon data) cho người dùng package.

Tôi đã đưa tệp phông chữ Mongolian (Mông Cổ) vào thư mục lib như thế này:

mongol
  lib/
    fonts/
      MQG8F02.ttf

Vì nó nằm trong thư mục lib/ nên nó sẽ tự động được đưa vào gói package. Nhưng vì tôi đang sử dụng nó trong package code để đặt làm phông chữ mặc định cho widget MongolText, tôi cũng đã khai báo nó trong pubspec.yaml:

flutter:
  fonts:
    - family: MenksoftQagan
      fonts:
        - asset: lib/fonts/MQG8F02.ttf

MenksoftQagan là tên mô tả. Tôi có thể đã gọi font family là HappyHippos nếu tôi muốn Mẹo tiếp theo là làm thế nào để cung cấp quyền truy cập vào phông chữ đó. Sử dụng MenksoftQagan là không đủ vì không chứa thông tin package. Cách giải quyết là sử dụng string pattern sau khi font family cần thiết:

'packages/<package_name>/<font_family_name>'

Đối với package của tôi, điều này được dịch sang

'packages/mongol/MenksoftQagan'

Trong package code, tôi đã tạo một class cho điều này:‌

class MongolFont {
  static const String qagan = 'packages/mongol/MenksoftQagan';                       }

5.1 Các developer sử dụng asset trong package như thế nào

Vì package sử dụng string 'packages/mongol/MenksoftQagan' trong nội bộ, người dùng package hoàn toàn không cần biết về nó.

Khai báo thư viện trong file pubspec.yaml:

dependencies:
  mongol: ^0.3.0

main.dart:

import 'package:flutter/material.dart';
import 'package:mongol/mongol_text.dart';
void main() => runApp(DemoApp());
class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('My App')),
        body: Stack(
          children: <Widget>[
            Center(
              child: MongolText(
                'ᠮᠣᠩᠭᠣᠯ',
                style: TextStyle(fontSize: 100),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Chạy ứng dụng mang lại điều này

một ứng dụng sử dụng package mongol

Tuy nhiên, nếu người dùng ứng dụng muốn sử dụng trực tiếp tệp phông chữ, họ có thể sử dụng string 'packages/mongol/MenksoftQagan' để truy cập nó. Ví dụ: thay thế widget MongolFont bằng widget Text chuẩn:

Text(
  'ᠮᠣᠩᠭᠣᠯ',
  style: TextStyle(
    fontFamily: 'packages/mongol/MenksoftQagan',
    fontSize: 100,
  ),
),

Nó cho ra:

sử dụng phông chữ trực tiếp từ gói asset package

Để được trợ giúp khi truy cập các loại tệp khác, hãy xem phần Hỏi và Đáp về Stack Overflow này.

Tóm lại:

Thật tuyệt khi các package Pub là open source để chúng ta có thể học hỏi bằng cách xem người khác giải quyết vấn đề tương tự như thế nào. Nếu bạn có cách để cải thiện quy trình thêm asset vào một package, trước tiên hãy kiểm tra vấn đề GitHub này. Và nếu có bất kỳ cải tiến hoặc thông tin nào có thể thêm vào bài viết này, vui lòng cho 200Lab biết nhé.

Bài viết được dịch từ đây.

You've successfully subscribed to 200Lab Blog
Great! Next, complete checkout for full access to 200Lab Blog
Xin chào mừng bạn đã quay trở lại
OK! Tài khoản của bạn đã kích hoạt thành công.
Success! Your billing info is updated.
Billing info update failed.
Your link has expired.