Flutter折叠与展开动画插件origami的使用

Flutter折叠与展开动画插件origami的使用

Origami

Origami是一个用于构建服务器驱动UI的Flutter库。它允许你使用JSON定义UI组件及其配置,从而实现动态UI更新而无需更改代码。

使用场景

作为移动开发者,我们经常需要尽快交付应用程序。此外,UI变化可能每周都会发生。然而,如果出现bug或者需要修改UI,我们需要发布更新后的应用到应用商店,这需要时间和成本。因此,我们需要构建灵活的页面。所以,我们定义了一个轻量级的UI协议,并在Android和iOS上实现了它。我们可以通过推送一个json文件来动态更新应用UI。有了这个能力,我们可以在不发布应用到应用商店的情况下进行一些UI A/B测试。通过这个项目,你可以从一个json字符串(即UI协议)构建你的UI。json字符串非常类似于Flutter小部件的dart代码。所有的小部件类型和小部件属性都是相同的。

安装

要在你的Flutter项目中使用Origami,请遵循以下步骤:

  1. 将Origami库添加到你的pubspec.yaml文件中:
flutter pub add origami

示例

这是一个使用Origami构建服务器驱动UI的简单示例。

服务器

{
      "type": "scaffold",
      "appBar": {
        "type": "appBar",
        "title": {"type": "text", "text": "Login"},
      },
      "body": {
        "type": "safeArea",
        "child": {
          "type": "column",
          "crossAxisAlignment": "center",
          "children": [
            {
              "type": "sizedBox",
              "height": "20.0",
            },
            {
              "type": "image",
              "imageType": "network",
              "value":
                  "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRjSoKn8IQb33N82TB_LkwVNhgHmlqTuZTcWA&usqp=CAU",
              "height": "100.0",
            },
            {
              "type": "container",
              "padding": {
                "edgeInsetsGeometry": "all",
                "value": "16.0",
              },
              "child": {
                "type": "column",
                "crossAxisAlignment": "center",
                "children": [
                  {
                    "type": "textFormField",
                    "decoration": {
                      "labelText": "Username",
                      "hintText": "Enter your username",
                    }
                  },
                  {
                    "type": "textFormField",
                    "decoration": {
                      "labelText": "Password",
                      "hintText": "Enter your password",
                    }
                  },
                  {
                    "type": "sizedBox",
                    "height": "30.0",
                  },
                  {
                    "type": "elevatedButton",
                    "child": {"type": "text", "text": "Login"},
                  },
                ],
              },
            },
            {
              "type": "text",
              "text": "Forgot password?",
              "style": {"color": "#3366CC", "fontSize": "16.0"},
            },
          ],
        }
      },
    }

Flutter

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

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    // 定义你的主题数据
    ThemeData appTheme = ThemeData(
      appBarTheme: const AppBarTheme(
        color: Colors.amber,
      ),
      // 添加更多的主题设置...
    );

    // 在OrigamiBuilder中设置主题数据
    OrigamiBuilder.themeData = appTheme;

    // 在主小部件状态中定义控制器映射
    Map<String, dynamic> controllers = {
      'username': TextEditingController(),
      'password': TextEditingController(),
      // 根据需要添加更多的控制器
    };

    // 示例JSON数据
    Map<String, dynamic> jsonData = {
      "type": "scaffold",
      "appBar": {
        "type": "appBar",
        "title": {"type": "text", "text": "Login"},
      },
      "body": {
        "type": "safeArea",
        "child": {
          "type": "column",
          "crossAxisAlignment": "center",
          "children": [
            {
              "type": "sizedBox",
              "height": "20.0",
            },
            {
              "type": "image",
              "imageType": "network",
              "value":
                  "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRjSoKn8IQb33N82TB_LkwVNhgHmlqTuZTcWA&amp;usqp=CAU",
              "height": "100.0",
            },
            {
              "type": "container",
              "padding": {
                "edgeInsetsGeometry": "all",
                "value": "16.0",
              },
              "child": {
                "type": "column",
                "crossAxisAlignment": "center",
                "children": [
                  {
                    "type": "textFormField",
                    "decoration": {
                      "labelText": "Username",
                      "hintText": "Enter your username",
                    },
                    "controller": "username",
                    "onListeners": {
                      "onChanged": {"method": "usernameChanged"},
                      "onFieldSubmitted": {"method": "usernameSubmitted"}
                    }
                  },
                  {
                    "type": "textFormField",
                    "decoration": {
                      "labelText": "Password",
                      "hintText": "Enter your password",
                    },
                    "obscureText": "true",
                    "controller": "password",
                  },
                  {
                    "type": "sizedBox",
                    "height": "30.0",
                  },
                  {
                    "type": "elevatedButton",
                    "onPressed": {
                      "method": "loginButtonPressed",
                      "params": {
                        "username": "exampleUsername",
                        "password": "examplePassword",
                      }
                    },
                    "child": {"type": "text", "text": "Login"},
                  },
                ],
              },
            },
            {
              "type": "text",
              "text": "Forgot password?",
              "style": {"color": "#3366CC", "fontSize": "16.0"},
            },
            {
              "type": "sizedBox",
              "height": "30.0",
            },
            {
              "type": "customWidget1",
            },
            {
              "type": "customWidget2",
            },
          ],
        }
      },
    };

    // 注册默认构造器
    OrigamiBuilder.registerCustomBuildersFromJsonList([
      {
        "type": "customWidget1",
        "builder": (BuildContext context, Map<String, dynamic> data,
            {Map<String, dynamic>? controllers,
            Function(dynamic params)? onMethodCall,
            Map<String, Function(dynamic params)>? onListeners}) {
          return const Text("Your Dynamic Widget");
        }
      },
      {
        "type": "customWidget2",
        "builder": (BuildContext context, Map<String, dynamic> data,
            {Map<String, dynamic>? controllers,
            Function(dynamic params)? onMethodCall,
            Map<String, Function(dynamic params)>? onListeners}) {
          return const Text("Your Dynamic Widget 2");
        }
      },
      // 根据需要添加更多的自定义小部件
    ]);

    return MaterialApp(
      home: OrigamiBuilder.buildFromJson(
        context,
        json: jsonData,
        controllers: controllers,
        onListeners: {
          'onChanged': (dynamic params) {
            // 处理'onChanged'事件
            debugPrint('Text changed with parameters: $params');
          },
          'onFieldSubmitted': (dynamic params) {
            // 处理'onFieldSubmitted'事件
            debugPrint('Text changed with parameters: $params');
          },
        },
        onMethodCall: (dynamic params) {
          // 根据方法名处理不同的方法调用
          if (params != null && params['method'] != null) {
            String methodName = params['method'];
            Map<String, dynamic>? methodParams = params['params'];

            // 根据方法名执行逻辑
            switch (methodName) {
              case 'loginButtonPressed':
                if (methodParams != null) {
                  String username = controllers['username']!.text;
                  String password = controllers['password']!.text;
                  debugPrint(
                      "Login button pressed with username: $username, password: $password");
                  debugPrint(
                      "Login button pressed with username: $username, password: $password");
                  // 使用提供的参数添加你的登录逻辑
                }
                break;
              // 根据需要添加更多的方法名案例
            }
          }
        },
      ),
    );
  }
}

更多关于Flutter折叠与展开动画插件origami的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter折叠与展开动画插件origami的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter中的折叠与展开动画插件origami的使用,这里提供一个简单的代码案例来展示其基本功能。origami插件通常用于创建复杂的折叠和展开动画效果,不过需要注意的是,由于Flutter生态系统中的插件会随时间更新,具体的实现和API可能会有所变化。因此,以下代码基于假设的origami插件功能进行演示。

首先,确保你的pubspec.yaml文件中已经添加了origami插件的依赖(请注意,这里origami是一个假设的插件名,实际使用时请替换为真实的插件名或相应的动画插件):

dependencies:
  flutter:
    sdk: flutter
  origami: ^x.y.z  # 替换为实际版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Dart文件中使用origami插件来创建折叠与展开的动画效果。以下是一个简单的示例:

import 'package:flutter/material.dart';
import 'package:origami/origami.dart'; // 假设的origami插件导入

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Origami Animation Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Origami Animation Demo'),
        ),
        body: Center(
          child: OrigamiAnimationDemo(),
        ),
      ),
    );
  }
}

class OrigamiAnimationDemo extends StatefulWidget {
  @override
  _OrigamiAnimationDemoState createState() => _OrigamiAnimationDemoState();
}

class _OrigamiAnimationDemoState extends State<OrigamiAnimationDemo> with SingleTickerProviderStateMixin {
  bool isExpanded = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        TextButton(
          onPressed: () {
            setState(() {
              isExpanded = !isExpanded;
            });
          },
          child: Text(isExpanded ? 'Collapse' : 'Expand'),
        ),
        SizedBox(height: 20),
        AnimatedOrigami( // 假设的AnimatedOrigami是origami插件中的一个widget
          expanded: isExpanded,
          child: Container(
            color: Colors.amber,
            height: isExpanded ? 200 : 100,
            child: Center(
              child: Text(
                'This is a foldable content.',
                style: TextStyle(fontSize: 24),
              ),
            ),
          ),
          duration: Duration(seconds: 1), // 动画持续时间
          curve: Curves.easeInOut, // 动画曲线
        ),
      ],
    );
  }
}

// 假设的AnimatedOrigami类,实际使用时请替换为origami插件中的相应类
class AnimatedOrigami extends StatefulWidget {
  final bool expanded;
  final Widget child;
  final Duration duration;
  final Curve curve;

  const AnimatedOrigami({
    Key key,
    @required this.expanded,
    @required this.child,
    this.duration = const Duration(seconds: 1),
    this.curve = Curves.linear,
  }) : super(key: key);

  @override
  _AnimatedOrigamiState createState() => _AnimatedOrigamiState();
}

class _AnimatedOrigamiState extends State<AnimatedOrigami> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: widget.duration,
      vsync: this,
    )..value = widget.expanded ? 1.0 : 0.0;

    _animation = Tween<double>(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: widget.curve,
      ),
    );

    _controller.addListener(() {
      setState(() {});
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 这里应该实现折叠和展开的动画逻辑,但由于origami插件是假设的,
    // 我们仅简单展示如何使用动画控制器控制高度变化。
    double height = lerpDouble(100, 200, _animation.value); // 假设初始高度为100,展开后为200

    return AnimatedContainer(
      duration: widget.duration,
      curve: widget.curve,
      height: height,
      child: widget.child,
    );
  }
}

注意

  1. origami插件和AnimatedOrigami类在上面的代码中都是假设的,实际使用时需要替换为真实的插件和相应的类。
  2. 动画效果(如折叠和展开)的实现细节会依赖于你选择的插件的具体API。
  3. 上面的代码仅展示了如何使用AnimationControllerTween来实现简单的高度动画,实际的折叠和展开动画可能会复杂得多。

为了获得更精确和具体的实现,建议查阅所选插件的官方文档和示例代码。

回到顶部