Flutter插件eblox的使用_EbloX是一个简单的 Flutter 状态管理库

Flutter插件eblox的使用_EbloX是一个简单的 Flutter 状态管理库

EbloX 是一个简单的 Flutter 状态管理库,类似于 Bloc,但它通过 ActionState 的概念将业务逻辑与 UI 分离开来,并大量使用了注解。它更简单、更可靠且更容易测试!

EbloX 图标

示例:通用计数器

添加依赖

pubspec.yaml 文件中添加以下依赖:

dependencies:
  eblox:
  eblox_annotation:

dev_dependencies:
  build_runner:
  eblox_generator:

然后运行以下命令生成代码:

flutter pub run build_runner watch --delete-conflicting-outputs

创建 counter_view_model.dart

import 'package:eblox/eblox.dart';
import 'package:eblox_annotation/eblox_annotation.dart';
import 'package:flutter/cupertino.dart';

part 'counter_view_model.g.dart';

@blox
class CounterVModel with Blox {

  @StateX(name: 'CounterState')
  int _counter = 0;

  @ActionX(bind: 'CounterState')
  void _add() async {
    _counter++;
  }

  @ActionX(bind: 'CounterState')
  void _sub() {
    _counter--;
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();
    debugPrint('CounterVModel dispose...');
  }
}

这段代码定义了一个简单的计数器模型,包含两个操作(_add_sub),并自动生成对应的 State 类。

创建 UI

import 'package:eblox/blox.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

import 'blox/counter_view_model.dart';

class CounterPage extends StatelessWidget {
  const CounterPage({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: BloxBuilder<CounterVModel, CounterState>(
          inject: (injection) => injection.inject(CounterVModel()),
          builder: (count) {
            return Center(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text("$count"),
                  ElevatedButton(
                    onPressed: () {
                      $$<CounterVModel>(AddAction());
                    },
                    child: const Text("+"),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      $$<CounterVModel>(SubAction());
                    },
                    child: const Text("-"),
                  ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}

这里使用了 BloxBuilder 来监听状态变化,并根据状态更新 UI。


使用说明

创建 ViewModel

我们需要创建一个类并混入 Blox,这是类似 MVVM 中的 ViewModel。注意需要为该类添加 @blox 注解。如果需要外部访问由 @StateX 注解生成的状态,还需要混入 _$className,例如:

class CounterVModel with Blox, _$CounterVModel {
  // ...
}

然后可以通过 $<CounterVModel>().counter 访问状态。

使用 @StateX

@StateX 用于装饰我们所需的状态,它会自动为我们生成一个带有指定名称的 State 类,用于封装修改后的数据。

@StateX(name: 'CounterState')
int _counter = 0;

如果不指定名称,则会根据默认规则生成 State 类名。

使用 @ActionX

@ActionX 用于生成 Action 类,可以指定名称,并通过 bind 指定与哪个 State 类关联。同时,它还会将装饰的方法与生成的 Action 关联起来,当发送 Action 时调用该方法。

@ActionX(bind: 'CounterState')
void _add() async {
  _counter++;
}

异步状态 @AsyncX

除了同步状态外,还支持异步状态,使用 @AsyncX 装饰:

@AsyncX(name: 'SongListState')
SongListModel _songModel = SongListModel();

@bindAsync
@ActionX(bind: 'SongListState')
BloxAsyncTask<SongListModel> _search(String name) {
  return () {
    return SearchService.search(name);
  };
}

UI 中处理异步状态

在 UI 中,我们可以使用 BloxView 来处理异步状态,它提供了 onLoadingonEmptyonErrorbuilder 方法来处理加载状态和数据展示。

class SearchPage extends StatelessWidget {
  SearchPage({Key? key}) : super(key: key);

  final TextEditingController _controller = TextEditingController();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Song search')),
      body: SafeArea(
        child: Column(
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                contentPadding: const EdgeInsets.symmetric(horizontal: 16),
                suffix: IconButton(
                  icon: const Icon(Icons.search_rounded),
                  onPressed: () {
                    if (_controller.text.isNotEmpty) {
                      $$<SearchVModel>(SearchAction(_controller.text));
                    }
                  },
                ),
              ),
            ),
            Flexible(
              child: BloxView<SearchVModel, SongListState<SongListModel>>(
                create: () => SearchVModel(),
                onLoading: () => const Center(child: CircularProgressIndicator()),
                onEmpty: () => const Center(child: Text("Empty")),
                builder: (state) {
                  return ListView.builder(
                    itemCount: state.data.songs.length,
                    itemBuilder: (ctx, i) {
                      return Container(
                        alignment: Alignment.center,
                        height: 40,
                        child: Text(
                          state.data.songs[i],
                          style: const TextStyle(color: Colors.blueGrey, fontSize: 20),
                        ),
                      );
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

如果希望 onEmpty 生效,则需要确保自定义的数据类型实现了 BloxData 接口:

class SongListModel with BloxData {
  SongListModel({UnmodifiableListView<String>? songs}) {
    if (songs != null) this.songs = songs;
  }

  UnmodifiableListView<String> songs = UnmodifiableListView([]);

  [@override](/user/override)
  bool get isEmpty => songs.isEmpty;
}

更多关于Flutter插件eblox的使用_EbloX是一个简单的 Flutter 状态管理库的实战教程也可以访问 https://www.itying.com/category-92-b0.html

回到顶部