Flutter自定义形状绘制插件shape的使用

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

Flutter自定义形状绘制插件shape的使用

本插件用于构建可轻松复用、验证和解析的表单。以下是关于如何使用该插件的具体说明。

目录

概要

此插件包含三个部分:

  • shape包 包含创建表单主体所需的主要类和注解。
  • shape_generator包,这是运行在带有 @GenerateFormBody() 注解的类上的代码生成器。
  • shape_starter_kit包,其中包含一组通用且常用的表单字段和函数,供 shape 包使用。

使用

首先,将 shape 包添加到项目的依赖项中。

dart pub add shape

然后,将 shape_generatorbuild_runner 包添加到项目的开发依赖项中。

dart pub add --dev shape_generator build_runner

注意 如果上述命令不起作用,可以考虑手动将包添加到 pubspec.yaml 文件中,将 shape 包置于 dependencies 下,将 shape_generatorbuild_runner 包置于 dev_dependencies 下。

为了生成一个名为 ExampleFormBody 的表单主体,可以按以下步骤操作:

  1. 创建一个带有 @GenerateFormBody() 注解的抽象类 ExampleFormBody
  2. 添加 _$ExampleFormBodyFields 混入类。
  3. 创建一个未命名的工厂方法,返回一个包含所有表单字段的 _$ExampleFormBody 实例。所有参数必须是一个扩展了 FormField 类的实例。

完整的示例代码可能如下所示:

import 'package:shape/shape.dart';
import 'package:shape_addons/shape_addons.dart';

part 'example_form_body.g.dart';

@GenerateFormBody()
abstract class ExampleFormBody with _$ExampleFormBodyFields {
  factory ExampleFormBody({
    required String? name,
    required int? age,
  }) {
    return _$ExampleFormBody(
      name: GenericFormField(
        value: name,
        isRequired: true,
      ),
      age: IntegerFormField(
        value: age,
      ),
    );
  }
}

void main() {
  final formBody = ExampleFormBody(name: 'John', age: 25);
  print('Example form: $formBody');
  print('Example form errors: ${formBody.validate()}');
}

原理

Shape 通过将表单字段、表单主体、验证逻辑和解析逻辑分离到不同的类中来工作。

表单主体是一组表单字段。数据进入和离开表单主体的流程如下:

flowchart TD
  classDef multipleValues fill:#f0f0f0,stroke:#000000,stroke-dasharray: 5;
  classDef classInstance fill:#eeeeff,stroke:#aaaaee
  classDef function fill:#d0efe6,stroke:#6cddbd

  raw{{Raw String values}}:::multipleValues
  fbc(Form body constructor):::function
  fbi[Form body instance]:::classInstance
  parsed{{Parsed values}}:::multipleValues
  fei[Form errors instance]:::classInstance

  raw -- "are given to" --> fbc
  fbc -- "parses fields and creates" --> fbi
  fbi -- "contains" --> parsed
  fbi -- "when calling validate() creates" --> fei

特性

访问解析后的值

表单主体接收原始值并生成解析后的值。每次表单主体被构造或复制(使用 copyWith)时,值会自动解析,并作为具有相同名称的属性可访问。

var formBody = ExampleFormBody(name: 'John');
print('Example form: $formBody');
print('Example form errors: ${formBody.validate()}');

自动生成表单错误

生成表单主体时,会同时创建一个相邻的 [FormErrors] 类,并可访问。

var formBody = ExampleFormBody(name: 'John');
print('Example form: $formBody');
print('Example form errors: ${formBody.validate()}');

示例

要运行示例,需要在 example 文件夹中运行 build_runner

cd example
flutter pub run build_runner build --delete-conflicting-outputs

基于 example/lib/example_form_body.dart 文件的内容,将生成一个新的表单主体。生成完成后,检查 example/lib/example_form_body.g.dart 文件的内容。

import 'package:shape_example/example_form_body.dart';

void main() {
  print(r'''
This project is not meant to be run like a normal Dart project, but instead
showcases how to generate form bodies using Shape.

Generate the form bodies by running:
  dart run build_runner build --delete-conflicting-outputs
''');

  final form = ExampleFormBody(name: 'John');
  print('Example form: $form');
  print('Example form errors: ${form.validate()}');

  final invalidForm = ExampleFormBody(name: null, age: 25);
  print('Invalid example form: $invalidForm');
  print('Invalid example form errors: ${invalidForm.validate()}');
}

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

1 回复

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


在Flutter中,自定义形状绘制通常涉及使用CustomPaintCustomPainter类。虽然Flutter社区中可能有多个用于绘制自定义形状的插件,但基于你的要求,这里我们不会依赖特定的插件,而是直接展示如何使用CustomPaintCustomPainter来绘制自定义形状。

以下是一个简单的例子,展示如何使用CustomPaintCustomPainter来绘制一个自定义的星形:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Custom Shape Example'),
        ),
        body: Center(
          child: CustomPaint(
            size: Size(200, 200), // 设置绘制区域的大小
            painter: StarPainter(), // 使用自定义的Painter类
          ),
        ),
      ),
    );
  }
}

class StarPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;

    // 星形的五个顶点
    final List<Offset> points = [
      Offset(size.width * 0.5, size.height * 0.2),
      Offset(size.width * 0.65, size.height * 0.5),
      Offset(size.width * 0.5, size.height * 0.8),
      Offset(size.width * 0.35, size.height * 0.5),
      Offset(size.width * 0.5, size.height * 0.2),
    ];

    // 绘制多边形
    final Path path = Path()
      ..moveTo(points[0].dx, points[0].dy)
      ..lineTo(points[1].dx, points[1].dy)
      ..lineTo(points[2].dx, points[2].dy)
      ..lineTo(points[3].dx, points[3].dy)
      ..close();

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // 如果painter的状态没有改变,返回false
    return false;
  }
}

在这个例子中,我们创建了一个StarPainter类,它继承自CustomPainter。在paint方法中,我们使用Path类来定义一个星形的路径,并使用CanvasdrawPath方法来绘制这个路径。星形的五个顶点通过Offset对象定义,这些顶点连接成一个多边形。

CustomPaint组件用于在Flutter的widget树中嵌入自定义绘制。我们通过设置CustomPaintsize属性来定义绘制区域的大小,并通过painter属性指定自定义的Painter类。

这个例子展示了如何在Flutter中不使用任何第三方插件来自定义绘制形状。如果你需要使用特定的插件(比如shape插件,尽管这不是Flutter官方或广泛认知的插件名),你应该查阅该插件的文档来了解其API和用法。不过,基于Flutter的灵活性和强大的绘图能力,大多数情况下,使用CustomPaintCustomPainter已经足够满足自定义绘制的需求。

回到顶部