Flutter 用于管理 MVC (模型-视图-控制器) 架构的小型内部包插件contra的使用

发布于 1周前 作者 yibo5220 最后一次编辑是 5天前 来自 Flutter

Flutter 用于管理 MVC (模型-视图-控制器) 架构的小型内部包插件contra的使用

Contra

coverage License: BSD-1-Clause

Contra 是一个用于管理 MVC (模型-视图-控制器) 架构的小型内部包。它目前仍在开发中,并将根据需要进行改进。其主要目标是将 Riverpod 与我们的控制器集成,从而提供一种有效管理项目的方式。

特性

  • ContraView: 一个可以包含多个视图并支持与控制器联动的部件。
  • ContraController: 一个用于存储大部分视图逻辑的控制器。
  • ContraWidget: 一个允许子部件轻松访问控制器的部件。
  • 内部忙碌状态管理: 每个控制器都有一个内部忙碌状态,用于跟踪视图的加载状态,方便设置视图的加载状态。

使用

ContraView 示例

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

  @override
  Widget build(BuildContext context) {
    return ContraViewBuilder(
      builder : (BuildContext context, RandomTextController controller){
        return Scaffold(
          appBar: AppBar(
            title: const Text('Contra 示例'),
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children : [
              Text(controller.text),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed:(){
                  controller.generateText();
                },
                child: const Text('生成'),
              ),
            ],
          ),
        );
      },
      controllerBuilder: () => RandomTextController(),
    );
  }
}

ContraController 示例

class RandomTextController extends ContraController{
  RandomTextController(): super();

  String get text => ref.watch(_textProvider);

  String _generateRandomDynamicText() {
    final random = Random();
    const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    return String.fromCharCodes(
      List.generate(8, (_) => characters.codeUnitAt(random.nextInt(characters.length))),
    );
  }

  void generateText(){
    var randomText = _generateRandomDynamicText();
    ref.read(_textProvider.notifier).state = randomText;
  }
}

final _textProvider = StateProvider((ref) => 'hello');

管理本地状态

Riverpod 不建议使用其提供器来管理本地状态,例如:

  • 表单状态
  • 选中的项
  • 动画
  • 一般情况下通过控制器处理的状态(如 TextEditingController)。

因此,我们为控制器添加了钩子支持,这意味着每个控制器都可以使用 Flutter 钩子。但请谨慎使用这些钩子。

final firstName = useState('Contra');

void update() {
  firstName.value = '支持钩子';
}

ContraWidget 示例

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

  @override
  Widget build(BuildContext context) {
    return ContraViewBuilder(
      builder : (BuildContext context, RandomTextController controller){
        return Scaffold(
          appBar: AppBar(
            title: const Text('Contra 示例'),
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children : [
              Text(controller.text),
              const SizedBox(height: 20),
              const RandomTextSubWidget(),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed:(){
                  controller.generateText();
                },
                child: const Text('生成'),
              ),
            ],
          ),
        );
      },
      controllerBuilder: () => RandomTextController(),
    );
  }
}

class RandomTextSubWidget extends ContraWidget<RandomTextController>{
  const RandomTextSubWidget({super.key});

  @override
  Widget build(BuildContext context, RandomTextController controller){
    return Text(
      '这是一个样式化的随机文本 ${controller.text}',
      style: Theme.of(context).textTheme.bodyLarge!.copyWith(
        color: Colors.amber,
        fontWeight: FontWeight.bold,
        fontStyle: FontStyle.italic,
      ),
    );
  }
}

内部忙碌状态管理示例

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

  @override
  Widget build(BuildContext context) {
    return ContraViewBuilder(
      builder : (BuildContext context, RandomTextController controller){
        return Scaffold(
          appBar: AppBar(
            title: const Text('Contra 示例'),
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children : [
              AnimatedCrossFade(
                firstChild: Text(controller.text),
                secondChild: const CircularProgressIndicator(),
                duration: const Duration(milliseconds: 2000),
                crossFadeState: controller.isBusy ? CrossFadeState.showSecond :  CrossFadeState.showFirst,
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed:(){
                  controller.generateText();
                },
                child: const Text('生成'),
              ),
            ],
          ),
        );
      },
      controllerBuilder: () => RandomTextController(),
    );
  }
}

class RandomTextController extends ContraController{
  RandomTextController(): super();

  String get text => ref.watch(_textProvider);

  Future<String> _generateRandomDynamicText() {
    final random = Random();
    const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    final generatedText =  String.fromCharCodes(
      List.generate(8, (_) => characters.codeUnitAt(random.nextInt(characters.length))),
    );

    return Future.value(generatedText);
  }

  void generateText() async {
    setBusy(true);
    var randomText = await _generateRandomDynamicText();
    ref.read(_textProvider.notifier).state = randomText;
    setBusy(false);
  }
}

final _textProvider = StateProvider((ref) => 'hello');

你还可以为不同的对象设置忙碌状态

class RandomTextController extends ContraController{
  RandomTextController(): super();

  String get text => ref.watch(_textProvider);

  Future<String> _generateRandomDynamicText() {
    final random = Random();
    const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    final generatedText =  String.fromCharCodes(
      List.generate(8, (_) => characters.codeUnitAt(random.nextInt(characters.length))),
    );

    return Future.value(generatedText);
  }

  void generateText() async {
    setBusyForObject('生成', true);
    var randomText = await _generateRandomDynamicText();
    ref.read(_textProvider.notifier).state = randomText;
    setBusyForObject('生成', false);
  }
}

final _textProvider = StateProvider((ref) => 'hello');

你也可以在运行异步函数时同时设置控制器的忙碌状态

class RandomTextController extends ContraController{
  RandomTextController(): super();

  String get text => ref.watch(_textProvider);

  Future<String> _generateRandomDynamicText() {
    final random = Random();
    const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    final generatedText =  String.fromCharCodes(
      List.generate(8, (_) => characters.codeUnitAt(random.nextInt(characters.length))),
    );

    return Future.value(generatedText);
  }

  void generateText() async {
    try{
      var randomText = await runBusyFuture(
        _generateRandomDynamicText(),
        throwException: true,
      );
      ref.read(_textProvider.notifier).state = randomText;
    } catch(e){
      // 处理错误
    }
  }
}

final _textProvider = StateProvider((ref) => 'hello');

更多关于Flutter 用于管理 MVC (模型-视图-控制器) 架构的小型内部包插件contra的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter 用于管理 MVC (模型-视图-控制器) 架构的小型内部包插件contra的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


由于contra这个Flutter插件的具体功能和用途在官方文档或社区中没有明确定义,我们只能基于插件名进行合理的推测。假设contra是一个与某种特定功能(比如数据加密、网络请求、UI组件等)相关的插件,我们可以编写一些示例代码来展示如何在一个Flutter项目中集成和使用一个假想的contra插件。

请注意,以下代码是基于假设编写的,实际使用时需要根据contra插件的真实功能和API进行调整。

1. 添加插件依赖

首先,在pubspec.yaml文件中添加contra插件的依赖(注意:这里的依赖名和版本号需要根据实际情况填写):

dependencies:
  flutter:
    sdk: flutter
  contra: ^x.y.z  # 假设的版本号

2. 导入插件

在你的Dart文件中导入contra插件:

import 'package:contra/contra.dart';

3. 使用插件

以下是一个假设的示例,展示如何使用contra插件进行某种操作(比如数据加密):

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

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

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

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  String encryptedText = '';
  String decryptedText = '';

  void encryptText() async {
    String originalText = "Hello, Flutter!";
    String key = "mySecretKey"; // 假设的加密密钥

    // 调用contra插件的加密方法(假设存在)
    String encrypted = await Contra.encrypt(originalText, key);
    
    setState(() {
      encryptedText = encrypted;
    });
  }

  void decryptText() async {
    String encrypted = encryptedText;
    String key = "mySecretKey"; // 假设的解密密钥

    // 调用contra插件的解密方法(假设存在)
    String decrypted = await Contra.decrypt(encrypted, key);
    
    setState(() {
      decryptedText = decrypted;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Contra Plugin Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Original Text: Hello, Flutter!'),
            SizedBox(height: 16),
            Text('Encrypted Text: $encryptedText'),
            SizedBox(height: 16),
            Text('Decrypted Text: $decryptedText'),
            SizedBox(height: 32),
            ElevatedButton(
              onPressed: encryptText,
              child: Text('Encrypt'),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: encryptedText.isEmpty ? null : decryptText,
              child: Text('Decrypt'),
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

  1. 实际API:上述代码中的Contra.encryptContra.decrypt方法是假设存在的,实际使用时需要查阅contra插件的官方文档来了解其真实API。
  2. 错误处理:在实际开发中,应该添加错误处理逻辑来捕获和处理可能发生的异常。
  3. 插件版本:确保你使用的contra插件版本与你的Flutter SDK版本兼容。

由于contra插件的具体功能和API未知,上述代码只是一个基于假设的示例。如果你已经安装了contra插件并且知道其真实功能,建议查阅其官方文档或示例代码来获取更准确的使用指南。

回到顶部