Flutter功能未知插件code_on_the_rocks的介绍与使用

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

Flutter功能未知插件code_on_the_rocks的介绍与使用

概述

Code on the Rocks库提供了一组简单的部件,帮助您将状态数据传递给子树。

  • ViewModel - 一个引入InheritedWidget到小部件树中的State对象。
  • ViewModelBuilder - 您将在小部件中包含的一个StatefulWidget。
  • ViewModelProvider - (幕后)一个为子项提供ViewModel的InheritedWidget。

在使用code_on_the_rocks构建时,您只需要关注ViewModel和ViewModelBuilder。ViewModelProvider会为您创建。

Code on the Rocks widget diagram

这种方法的好处是所有子树内的子项都可以访问ViewModel——这就是InheritedWidgets的工作方式。

根据应用程序的需求,您可以将ViewModelBuilder放置在应用程序的小部件树中的任意位置,从而方便地将服务、常量等传递到整个应用程序。

好处

💙 纯Flutter

ViewModelProvidersInheritedWidgets,这意味着您可以使用Flutter框架内置的方法来访问它们。由于ViewModel是ViewModelProvider上的一个属性,您可以使用上下文方法dependOnInheritedWidgetOfExactType来访问它。这个包为您设置了这些,所以您可以这样做:

HomeViewModel model = HomeViewModel().of(context);
🍋 易于模型使用

ViewModelProvider通过其builder属性为其子项提供您的模型,因此大多数时候您不需要添加代码来访问模型。

return Scaffold(
  body: HomeViewModelBuilder(
    builder: (context, model) {
      return ... // 使用模型渲染UI
    },
  ),
);
🔥 无膨胀

整个库只有60行Dart代码,没有外部依赖。

设置

步骤1: 创建一个ViewModel。ViewModel是一个引入InheritedWidget到小部件树中的State对象。这是您的业务逻辑所在的地方。

class HomeViewModel extends ViewModel<HomeViewModel> {

  // 为了方便,可以添加一个静态.of_获取器。这是可选的
  static HomeViewModel of_(BuildContext context) => getModel<HomeViewModel>(context);

  // 在这里添加您的业务逻辑和状态属性
  // 注意在这里您可以访问setState
  ValueNotifier<int> counter = ValueNotifier(0);

  void incrementCounter() {
    setState(() {
      counter.value++;
    });
  }
}

步骤2: 创建一个ViewModelBuilderViewModelBuilder是一个您将在小部件树中包含的StatefulWidget。ViewModelBuilder从上面创建了ViewModel。

class HomeViewModelBuilder extends ViewModelBuilder<HomeViewModel> {
  const HomeViewModelBuilder({
    super.key,
    required super.builder,
  });

  // 覆盖createState以创建上面的特定ViewModel
  [@override](/user/override)
  State<StatefulWidget> createState() => HomeViewModel();
}

使用

一旦您有了ViewModel和ViewModelBuilder,将ViewModelBuilder添加到您的小部件树中:

return Scaffold(
  body: HomeViewModelBuilder(
    builder: (context, model) {
      return Text('Test');
    },
  ),
);

现在您有几种方法可以访问ViewModel。

1. 使用提供的“model”对象:
return Scaffold(
  body: HomeViewModelBuilder(
    builder: (context, model) {
      return Text(model.title); // 在您的ViewModel中添加一个标题字符串
    },
  ),
);
2. 使用getModel<T>辅助函数:
return Scaffold(
  body: HomeViewModelBuilder(
    builder: (context, model) {
      return Text(getModel<HomeViewModel>(context).title); // 在您的ViewModel中添加一个标题字符串
    },
  ),
);
3. 使用ModelWidget:
ModelWidget<ScreenTwoViewModel>(
  builder: (context, model) {
    return Text(model.counter.value.toString());
  },
)
4. 使用.of(context)方法:
return Scaffold(
  body: HomeViewModelBuilder(
    builder: (context, model) {
      return Text(HomeViewModel().of(context).title); // 在您的ViewModel中添加一个标题字符串
    },
  ),
);

.of(context)方法只适用于ViewModel的实例,因为静态成员不能引用类的类型参数。如果您想节省输入额外括号的时间,在您的ViewModel中直接添加一个单独的方法(类不能有相同名称的实例和静态方法,因此“.of_” vs “.of”):

class HomeViewModel extends ViewModel<HomeViewModel> {

  // 添加此方法
  static HomeViewModel of_(BuildContext context) => getModel<HomeViewModel>(context);
}

要更新UI在ViewModel更改后,有两个选项:

  1. 调用setState重建ViewModelBuilder内的整个小部件树。
  2. 使用ValueNotifiers和ValueListenableBuilders的组合选择性地重建UI的部分。

您可以在示例目录中看到每种方法的示例。

高级使用

初始化和销毁

由于ViewModel对象扩展了State类,您可以简单地覆盖initStatedispose来运行当ViewModel被添加和从小部件树移除时的代码,分别:

class HomeViewModel extends ViewModel<HomeViewModel> {

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

  [@override](/user/override)
  void dispose() {
    debugPrint('Dispose');
    super.dispose();
  }
}
设置加载

ViewModels包括一个可以用来标记其为“加载”的单个ValueNotifier:

ValueNotifier<bool> loading = ValueNotifier(false);

bool get isLoading => loading.value;

void setLoading(bool val) {
  setState(() {
    loading.value = val;
  });
}

例如,当ViewModel需要加载异步数据时,调用model.setLoading(true)。当数据加载完毕时,调用model.setLoading(false)。在您的UI中,如果加载值为true,则可以直接使用模型显示一个旋转器。每当加载值改变时,ViewModelBuilder内的整个UI都会被重建。

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return HomeViewModelBuilder(
      builder: (context, model) {
        return Scaffold(
          appBar: AppBar(title: Text(model.title)),
          body: Stack(
            children: [
              Text('Hello World!'),
              if (model.isLoading) const ColoredBox(color: Colors.black12, child: Center(child: CircularProgressIndicator()))
            ],
          ),
        );
      },
    );
  }
}

完整示例Demo

以下是一个完整的示例demo,展示如何使用code_on_the_rocks插件:

import 'package:code_on_the_rocks/code_on_the_rocks.dart';
import 'package:flutter/material.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Code on the Rocks',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const HomeView(),
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return HomeViewModelBuilder(
      builder: (context, model) {
        return Scaffold(
          appBar: AppBar(
            title: Text(model.title),
          ),
          body: Stack(
            children: [
              Center(
                child: Padding(
                  padding: const EdgeInsets.all(24.0),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      ValueListenableBuilder(
                        valueListenable: model.counter,
                        builder: (context, value, child) => Row(
                          children: [
                            const Text('ValueListenableBuilder: '),
                            const SizedBox(width: 8),
                            Text(value.toString()),
                          ],
                        ),
                      ),
                      const SeparatedCounter(),
                      const ModelWidgetCounter(),
                      const SizedBox(height: 16),
                      ElevatedButton(
                        onPressed: model.isLoading
                            ? () {}
                            : () async {
                                HomeViewModel()
                                    .of(context)
                                    .incrementCounterWithSetState();
                                model.setLoading(false);
                              },
                        child: const Text('Increment using setState'),
                      ),
                      ElevatedButton(
                        onPressed: model.isLoading
                            ? () {}
                            : () {
                                model.incrementCounterWithValueNotifier();
                              },
                        child: const Text('Increment using ValueNotifier'),
                      )
                    ],
                  ),
                ),
              ),
              if (model.isLoading)
                const ColoredBox(
                    color: Colors.black12,
                    child: Center(child: CircularProgressIndicator()))
            ],
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const ScreenTwoView(),
                ),
              );
            },
            child: const Icon(Icons.navigate_next),
          ),
        );
      },
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Text('SeparatedCounter: '),
        const SizedBox(width: 8),
        Text(HomeViewModel().of(context).counter.value.toString()),
      ],
    );
  }
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ModelWidget<HomeViewModel>(builder: (context, model) {
      return Row(
        children: [
          const Text('ModelWidgetCounter: '),
          const SizedBox(width: 8),
          Text(model.counter.value.toString()),
        ],
      );
    });
  }
}

class HomeViewModelBuilder extends ViewModelBuilder<HomeViewModel> {
  const HomeViewModelBuilder({
    super.key,
    required super.builder,
  });

  [@override](/user/override)
  State<StatefulWidget> createState() => HomeViewModel();
}

class HomeViewModel extends ViewModel<HomeViewModel> {
  static HomeViewModel of_(BuildContext context) =>
      getModel<HomeViewModel>(context);

  final String title = 'Home';

  ValueNotifier<int> counter = ValueNotifier(0);

  Future<void> incrementCounterWithSetState() async {
    setState(() {
      counter.value = counter.value + 1;
    });
  }

  void incrementCounterWithValueNotifier() {
    counter.value++;
  }

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

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

更多关于Flutter功能未知插件code_on_the_rocks的介绍与使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter功能未知插件code_on_the_rocks的介绍与使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


Flutter 功能未知插件 code_on_the_rocks 介绍与使用

code_on_the_rocks 是一个假定存在的 Flutter 插件,尽管它可能不是一个真实存在的插件,但为了符合你的要求,我将以一个假设的插件为例,展示如何介绍和使用它。假设 code_on_the_rocks 插件提供了一些高级功能,比如处理复杂的动画效果、数据可视化或集成第三方服务等。

插件介绍

code_on_the_rocks 是一个功能强大的 Flutter 插件,旨在帮助开发者轻松实现复杂的 UI 动画、数据可视化以及与第三方服务的集成。它提供了丰富的 API,使得开发者能够快速地构建出引人入胜的用户界面和高效的数据处理逻辑。

使用步骤

  1. 添加依赖

    首先,你需要在 pubspec.yaml 文件中添加 code_on_the_rocks 插件的依赖。请注意,由于这是一个假设的插件,下面的依赖项是虚构的。

    dependencies:
      flutter:
        sdk: flutter
      code_on_the_rocks: ^1.0.0
    

    然后运行 flutter pub get 命令来安装插件。

  2. 导入插件

    在你的 Dart 文件中导入 code_on_the_rocks 插件。

    import 'package:code_on_the_rocks/code_on_the_rocks.dart';
    
  3. 使用插件功能

    假设 code_on_the_rocks 插件提供了一个 ComplexAnimation 类来处理复杂的动画效果,下面是一个简单的使用示例:

    import 'package:flutter/material.dart';
    import 'package:code_on_the_rocks/code_on_the_rocks.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Code On The Rocks Example'),
            ),
            body: Center(
              child: ComplexAnimationExample(),
            ),
          ),
        );
      }
    }
    
    class ComplexAnimationExample extends StatefulWidget {
      @override
      _ComplexAnimationExampleState createState() => _ComplexAnimationExampleState();
    }
    
    class _ComplexAnimationExampleState extends State<ComplexAnimationExample> with SingleTickerProviderStateMixin {
      late AnimationController _controller;
      late Animation<double> _animation;
    
      @override
      void initState() {
        super.initState();
        _controller = AnimationController(
          duration: const Duration(seconds: 2),
          vsync: this,
        )..repeat(reverse: true);
    
        _animation = ComplexAnimation.createComplexAnimation(_controller);
      }
    
      @override
      void dispose() {
        _controller.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return AnimatedBuilder(
          animation: _animation,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
          builder: (context, child) {
            return Transform.scale(
              scale: _animation.value,
              child: child,
            );
          },
        );
      }
    }
    
    // 假设 ComplexAnimation 类提供了 createComplexAnimation 静态方法
    extension ComplexAnimation on AnimationController {
      Animation<double> createComplexAnimation(AnimationController controller) {
        // 这里实现复杂的动画逻辑
        return Tween<double>(begin: 0.0, end: 2.0).animate(CurvedAnimation(
          parent: controller,
          curve: Curves.easeInOut,
        ));
      }
    }
    

    在这个示例中,我们创建了一个 ComplexAnimationExample 组件,它使用 code_on_the_rocks 插件提供的 ComplexAnimation 类来创建一个复杂的动画效果。请注意,由于 code_on_the_rocks 是一个假设的插件,因此 ComplexAnimation 类和 createComplexAnimation 方法也是虚构的。在实际使用中,你需要根据插件提供的 API 文档来实现相应的功能。

  4. 运行应用

    最后,运行你的 Flutter 应用,你将看到一个带有复杂动画效果的界面。

结论

尽管 code_on_the_rocks 是一个假设的 Flutter 插件,但通过上述步骤,你可以了解如何添加、导入和使用一个 Flutter 插件的基本流程。在实际开发中,你需要根据插件的官方文档来了解其提供的 API 和使用方法。

回到顶部