Flutter资源加载插件loader的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter资源加载插件loader的使用

有时在构建你的小部件之前需要加载一些数据。因为initState不支持异步加载,所以你需要找到另一种方法来加载你的数据。最常见的加载数据的方法是使用FutureBuilder,但FutureBuilders很繁琐。另一种方法是使用标志在所有加载完成后重建小部件。

Loader 使用了标志方法。

LoadingMixin

LoadingMixin为你的有状态小部件的状态添加了所有必要的标志,将其转换为类似于FutureBuilder的小部件。

load是在第一个didChangeDependencies之前调用的,因此你可以使用context访问继承的小部件。

有两个标志:

  1. loading: 如果加载函数仍在运行,则为true
  2. hasError: 如果加载函数抛出异常,则为true

异常文本存储在error变量中。

class HomePage extends StatefulWidget {
  [@override](/user/override)
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with LoadingMixin<HomePage> {
  Data _data;

  // 加载数据
  [@override](/user/override)
  Future<void> load() async {
    var loader = FileLoader(); // 假设有一个FileLoader类
    _data = await loader.loadData();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    Widget body;
    if (loading) {
      body = Container(); // 显示加载指示器或空白容器
    } else if (hasError) {
      body = Text(error); // 显示错误信息
    } else {
      body = DataViewer(_data); // 显示数据
    }
    
    return Scaffold(
      appBar: AppBar(),
      body: body,
    );
  }
}

StatelessLoadingMixin

为了使这个混合类工作,你需要删除build方法并使用futureBuild方法代替。

class FutureText extends StatelessWidget with StatelessLoadingMixin {
  final Future<String> futureText;
  final TextStyle style;

  FutureText(this.futureText, {this.style});

  String text;

  [@override](/user/override)
  Future<void> load() async {
    text = await futureText; // 加载文本
  }

  [@override](/user/override)
  Widget futureBuild(BuildContext context) {
    return Text(
      text,
      style: style,
    ); // 显示加载后的文本
  }
}

Loader

Loader 是一个使用LoadingMixin混合类的小部件。

此小部件仅在加载函数完成后才会运行其构建方法。

构建器将获取加载函数返回的值作为value参数。

class Banner extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Loader<String>(
          load: () async {
            return await retrieveBannerText(); // 异步加载横幅文本
          },
          builder: (context, value){
            return Text(value); // 显示加载后的文本
          },
          errorBuilder: (error) => Text(error, style: TextStyle(color: Colors.red),), // 显示错误信息
        ),
      ),
    );
  }
}

实现细节

StatelessLoadingMixin是使用Loader小部件实现的。

Loader小部件是使用LoadingMixin实现的。

LoadingMixin是使用有状态小部件上的标志实现的。

完整示例Demo

以下是一个完整的示例,展示了如何使用Loader插件进行资源加载。

import 'package:flutter/material.dart';
import 'package:loader/src/loadingMixin.dart'; // 假设你已经安装了loader插件

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

class LoaderApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  [@override](/user/override)
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(kToolbarHeight),
        child: UserAppBar(),
      ),
      body: PostsPage(),
    );
  }
}

class UserAppBar extends StatefulWidget {
  [@override](/user/override)
  _UserAppBarState createState() => _UserAppBarState();
}

class _UserAppBarState extends State<UserAppBar> with LoadingMixin<UserAppBar> {
  late String _username;

  [@override](/user/override)
  Future<void> load() async {
    _username = await getUsername(); // 模拟异步获取用户名
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return AppBar(
      title: Text(loading ? '...' : hasError ? 'error' : _username), // 根据加载状态显示不同内容
    );
  }
}

class PostsPage extends StatefulWidget {
  [@override](/user/override)
  _PostsPageState createState() => _PostsPageState();
}

class _PostsPageState extends State<PostsPage> with LoadingMixin<PostsPage> {
  late List<Post> _posts;

  [@override](/user/override)
  Future<void> load() async {
    _posts = await getPosts(); // 模拟异步获取帖子列表
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    if (loading) return Center(child: Text('loading...')); // 显示加载提示
    if (hasError) return Text('an error occurred: $error'); // 显示错误信息
    return ListView(
      children: _posts
          .map(
            (post) => ListTile(
              title: Text(post.title), // 显示每个帖子的标题
            ),
          )
          .toList(),
    );
  }
}

class Post {
  final String title;

  Post(this.title);
}

Future<List<Post>> getPosts() async {
  return await Future.delayed(
      Duration(milliseconds: 3800),
      () => [
            Post('Flutter 2.0 released!'),
            Post('Flutter 1.12 released!'),
            Post('Dart 2.7 released!'),
            Post('Flutter 1.9 released!'),
            Post('Flutter 1.8 released!'),
            Post('Flutter 1.1 released!'),
            Post('Flutter 1.0 released!'),
          ]);
}

Future<String> getUsername() async {
  return await Future.delayed(Duration(seconds: 2), () => 'Aligator');
}

更多关于Flutter资源加载插件loader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter资源加载插件loader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,资源加载插件(如flutter_assets_loader或类似的自定义资源加载器)通常用于动态加载应用资源,如图片、音频、视频等。虽然没有一个广泛认可的标准插件名为flutter_assets_loader,但我们可以创建一个自定义的示例来展示如何在Flutter中动态加载资源。

以下是一个简单的示例,展示如何创建一个自定义资源加载器,并使用它加载本地图片资源。请注意,这个例子假设你已经有了一个包含资源的文件夹,并且你希望通过代码动态加载这些资源。

1. 创建资源文件夹

首先,在你的Flutter项目的assets文件夹中创建一个子文件夹,比如images,并放入一些图片资源。

your_flutter_project/
├── assets/
│   └── images/
│       ├── image1.png
│       ├── image2.png
│       └── ...

2. 更新pubspec.yaml

pubspec.yaml文件中,声明你想要加载的资源文件夹。

flutter:
  assets:
    - assets/images/

3. 创建资源加载器

虽然Flutter本身提供了AssetImage等类来加载资源,但为了模拟一个自定义加载器,我们可以创建一个简单的封装。

import 'dart:ui' as ui;
import 'package:flutter/material.dart';

class AssetLoader {
  Future<ui.Image> loadImage(String assetPath) async {
    final ByteData data = await rootBundle.load(assetPath);
    final Uint8List bytes = data.buffer.asUint8List();
    final ui.Codec codec = await ui.instantiateImageCodec(bytes);
    final ui.FrameInfo frameInfo = await codec.getNextFrame();
    return frameInfo.image;
  }
}

4. 使用资源加载器

在你的Flutter应用中,使用AssetLoader类来加载图片资源,并将其显示在一个Image组件中。

import 'package:flutter/material.dart';
import 'asset_loader.dart'; // 假设你的加载器类在这个文件中

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Asset Loader Example'),
        ),
        body: Center(
          child: FutureBuilder<ui.Image>(
            future: AssetLoader().loadImage('assets/images/image1.png'),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasError) {
                  return Text('Error loading image');
                } else {
                  return Image.memory(
                    snapshot.data!.toByteData(format: ui.ImageByteFormat.png)!.buffer.asUint8List(),
                    scale: 1.0,
                  );
                }
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }
}

注意事项

  1. 异步加载:资源加载是异步的,因此使用FutureBuilder或类似的异步组件来管理加载状态。
  2. 内存管理:对于大型资源,确保在不需要时释放内存,以避免内存泄漏。
  3. 错误处理:处理可能的加载错误,如文件未找到或解码失败。

这个示例展示了如何创建一个基本的资源加载器,并动态加载和显示图片资源。根据你的具体需求,你可能需要扩展这个加载器以支持更多类型的资源或更复杂的加载逻辑。

回到顶部