Flutter自定义UI构建插件body_builder的使用

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

Flutter 自定义 UI 构建插件 body_builder 的使用

BodyBuilder 是一个管理数据加载的组件。对于每种情况,该组件会根据包含所有必要信息的 BodyState 进行重建,以便正确显示相应的组件。

开始之前

BodyBuilder 通过三种不同的方式管理数据加载:状态(state)、缓存(cache)和数据(data):

  • 状态(state) 是一个 ChangeNotifier,其中包含已检索的数据。BodyBuilder 会监听它并在状态更改时进行重建。
  • 缓存(cache) 是一个 Future,如果状态为空,则在显示加载组件之前调用它并返回一个可空值。
  • 数据(data) 是一个 Future,如果状态为空,则调用它。如果发生错误,则显示错误组件。

分页数据也得到了支持(参见示例应用)。

简单使用

以下是如何使用 BodyBuilder 组件的一个简单示例。

如果你希望 BodyBuilder 显示加载和错误组件:

BodyBuilder(
    providers: [
        BodyProvider(
            state: _state,
            cache: _cacheProvider,
            data: _dataProvider,
        )
    ],
    builder: (String data) => Center(child: Text(data)),
);

如果你希望自行管理加载和错误组件,可以使用 customBuilder,它提供了 BodyState 来显示正确的组件:

BodyBuilder(
    key: _key,
    providers: [
        BodyProvider(
            state: _state,
            cache: _cacheProvider,
            data: _dataProvider,
        )
    ],
    customBuilder: (BodyState state) => Center(child: Text('data: ${state.data} (isCache: ${state.isCache}), error: ${state.error}, loading: ${state.loading}')),
);

你可以通过 loadingBuildererrorBuilder 覆盖默认的加载和错误组件。

你还可以通过 BodyBuilder.setDefaultConfig 配置所有 BodyBuilder

工作原理

状态提供器(StateProvider)

有几个状态提供器可以帮助你在不同情况下处理数据。

  • SimpleStateProvider 可以用于处理单个值。(例如:从服务器获取配置)

    BodyProvider(
        state: context.read<BasicSampleState>(),
        ...
    )
    
  • RelatedStateProvider 是一个带有你选择键的 SimpleStateProvider 的映射。(例如:你想按用户ID排序获取多个用户)

    BodyProvider(
        state: context.read<MultiProviderSampleState>().byId(...),
        ...
    )
    
  • PaginatedState 允许你检索分页数据列表。(查看示例应用)

    BodyProvider(
        state: context.read<YourRelatedPaginatedStates>().byId(...),
        ...
    )
    
  • ChangeNotifierExt.map 允许你通过 map 函数将任何 ChangeNotifier 转换为 StateProvider

    final StateProvider<...> state = context.read<YouState>().map((YouState state) => state.someValue);
    

额外信息

如果你发现了一个 bug 或者想要添加一个功能,请在 GitHub 上提交问题 这里


完整示例 Demo

以下是完整的示例代码:

import 'package:body_builder/body_builder.dart';
import 'package:body_builder_example/basic_sample_page.dart';
import 'package:body_builder_example/custom_builder_page.dart';
import 'package:body_builder_example/multi_providers_page.dart';
import 'package:body_builder_example/paginated_page.dart';
import 'package:body_builder_example/search_sample_page.dart';
import 'package:body_builder_example/states.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  BodyBuilder.setDefaultConfig(debugLogsEnabled: true);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => BasicSampleState()),
        ChangeNotifierProvider(create: (_) => MultiProviderSampleState()),
        ChangeNotifierProvider(create: (_) => PaginatedSampleState()),
        ChangeNotifierProvider(create: (_) => SearchSampleState()),
      ],
      child: MaterialApp(
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
          appBarTheme: AppBarTheme(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          ),
        ),
        home: const MyHomePage(title: 'Body Builder - Example'),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const BasicBodyBuilderPage(),
                  ),
                );
              },
              child: const Text('Basic example'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const CustomBuilderPage(),
                  ),
                );
              },
              child: const Text('Custom builder example'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const MultiProversPage(),
                  ),
                );
              },
              child: const Text('Multi providers example'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const PaginatedPage(),
                  ),
                );
              },
              child: const Text('Pagination example'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => const SearchSamplePage(),
                  ),
                );
              },
              child: const Text('Search example'),
            ),
            const Divider(),
            ElevatedButton(
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.orange),
              ),
              onPressed: () {
                context.read<BasicSampleState>().clear();
                context.read<MultiProviderSampleState>().clear();
                context.read<PaginatedSampleState>().clear();
                context.read<SearchSampleState>().clear();

                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text('All states cleared!')),
                );
              },
              child: const Text('Clear states'),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter自定义UI构建插件body_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义UI构建插件body_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用Flutter自定义UI构建插件body_builder的示例代码。body_builder插件假设是一个用于简化页面主体内容构建的自定义插件(请注意,由于body_builder并非一个广泛认知的官方或主流插件,以下示例将基于假设的功能进行构建,以展示如何设计和使用一个类似的插件)。

首先,我们需要创建一个Flutter项目,并假设body_builder插件已经添加到了项目的pubspec.yaml文件中。如果它是一个假想的插件,我们可以模拟其功能。

1. 添加依赖(假设body_builder已存在)

pubspec.yaml中添加依赖:

dependencies:
  flutter:
    sdk: flutter
  body_builder: ^1.0.0  # 假设版本号

2. 使用body_builder插件

假设body_builder插件提供了一个BodyBuilder widget,允许我们通过简单的配置来构建复杂的UI。以下是如何使用它的示例代码:

import 'package:flutter/material.dart';
import 'package:body_builder/body_builder.dart';  // 假设导入路径

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 配置BodyBuilder的参数
    final bodyBuilderConfig = BodyBuilderConfig(
      // 假设的配置项,例如背景颜色、主体内容等
      backgroundColor: Colors.white,
      title: 'Hello, Body Builder!',
      body: Column(
        children: <Widget>[
          Text('This is a custom UI built using body_builder plugin.'),
          ElevatedButton(
            onPressed: () {
              // 按钮点击事件
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Button tapped!')),
              );
            },
            child: Text('Tap Me'),
          ),
        ],
      ),
    );

    return Scaffold(
      appBar: AppBar(
        title: Text('Body Builder Example'),
      ),
      // 使用BodyBuilder widget并传入配置
      body: BodyBuilder(config: bodyBuilderConfig),
    );
  }
}

// 假设BodyBuilderConfig是一个配置类
class BodyBuilderConfig {
  final Color backgroundColor;
  final String title;
  final Widget body;

  BodyBuilderConfig({
    required this.backgroundColor,
    required this.title,
    required this.body,
  });
}

// 假设BodyBuilder widget的实现
class BodyBuilder extends StatelessWidget {
  final BodyBuilderConfig config;

  BodyBuilder({required this.config});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: config.backgroundColor,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Text(
              config.title,
              style: TextStyle(fontSize: 24),
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: config.body,
            ),
          ),
        ],
      ),
    );
  }
}

解释

  1. 配置类BodyBuilderConfig:这个类用于封装BodyBuilder widget的配置信息,例如背景颜色、标题和主体内容。

  2. BodyBuilder widget:这个widget接受一个BodyBuilderConfig对象作为参数,并根据这些配置信息构建UI。

  3. MyHomePage中使用BodyBuilder:我们创建了一个BodyBuilderConfig对象,并通过BodyBuilder widget将其传递给页面主体。

注意

  • 由于body_builder并非一个真实存在的插件,上述代码是一个模拟实现。
  • 如果body_builder真实存在,请参考其官方文档以获取准确的用法和API。

希望这个示例能够帮助你理解如何在Flutter中自定义和使用UI构建插件。如果你有更多具体需求或问题,请随时提问!

回到顶部