Flutter动画开关插件reactive_animated_toggle_switch的使用

Flutter动画开关插件reactive_animated_toggle_switch的使用

reactive_animated_toggle_switch 是一个基于 animated_toggle_switch 的包装库,可以与 reactive_forms 结合使用。目前文档还在编写中,可以查看 example 文件夹中的示例代码来了解如何使用。

示例代码

import 'package:flutter/material.dart';
import 'package:reactive_animated_toggle_switch/reactive_animated_toggle_switch.dart';
import 'package:reactive_forms/reactive_forms.dart';

// 自定义图标生成器
Widget rollingIconBuilder(int? value, bool foreground) {
  return Icon(iconDataByValue(value));
}

// 根据值返回对应的图标数据
IconData iconDataByValue(int? value) => switch (value) {
      0 => Icons.access_time_rounded,
      1 => Icons.check_circle_outline_rounded,
      2 => Icons.power_settings_new_rounded,
      _ => Icons.lightbulb_outline_rounded,
    };

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

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

  // 构建表单
  FormGroup buildForm() => fb.group({
        'rolling': FormControl<int>(value: 2),
        'size': FormControl<int>(value: 2),
        'dual': FormControl<bool>(value: false),
        'custom': FormControl<bool>(value: false),
      });

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(),
        body: SafeArea(
          child: SingleChildScrollView(
            physics: const BouncingScrollPhysics(),
            padding: const EdgeInsets.symmetric(
              horizontal: 20.0,
              vertical: 20.0,
            ),
            child: ReactiveFormBuilder(
              form: buildForm,
              builder: (context, form, child) {
                return Column(
                  children: [
                    // 滚动类型的动画开关
                    ReactiveAnimatedToggleSwitchRolling<int, int>(
                      formControlName: 'rolling',
                      values: const [0, 1, 2, 3],
                      iconBuilder: rollingIconBuilder,
                    ),
                    // 自定义样式的动画开关
                    ReactiveCustomAnimatedToggleSwitch<bool, bool>(
                      formControlName: 'custom',
                      values: const [false, true],
                      spacing: 0.0,
                      indicatorSize: const Size.square(30.0),
                      animationDuration: const Duration(milliseconds: 200),
                      animationCurve: Curves.linear,
                      iconBuilder: (context, local, global) {
                        return const SizedBox();
                      },
                      cursors: const ToggleCursors(
                        defaultCursor: SystemMouseCursors.click,
                      ),
                      iconsTappable: false,
                      wrapperBuilder: (context, global, child) {
                        return Stack(
                          alignment: Alignment.center,
                          children: [
                            Positioned(
                              left: 10.0,
                              right: 10.0,
                              height: 20.0,
                              child: DecoratedBox(
                                decoration: BoxDecoration(
                                  color: Color.lerp(
                                    Colors.black26,
                                    Theme.of(context).colorScheme.background,
                                    global.position,
                                  ),
                                  borderRadius: const BorderRadius.all(
                                    Radius.circular(50.0),
                                  ),
                                ),
                              ),
                            ),
                            child,
                          ],
                        );
                      },
                      foregroundIndicatorBuilder: (context, global) {
                        return SizedBox.fromSize(
                          size: global.indicatorSize,
                          child: DecoratedBox(
                            decoration: BoxDecoration(
                              color: Color.lerp(
                                Colors.white,
                                Theme.of(context).primaryColor,
                                global.position,
                              ),
                              borderRadius: const BorderRadius.all(
                                Radius.circular(50.0),
                              ),
                              boxShadow: const [
                                BoxShadow(
                                  color: Colors.black38,
                                  spreadRadius: 0.05,
                                  blurRadius: 1.1,
                                  offset: Offset(0.0, 0.8),
                                )
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                    // 自定义大小的动画开关
                    ReactiveAnimatedToggleSwitchSize<int, int>(
                      formControlName: 'size',
                      style: ToggleStyle(
                        backgroundColor: const Color(0xFF919191),
                        indicatorColor: const Color(0xFFEC3345),
                        borderColor: Colors.transparent,
                        borderRadius: BorderRadius.circular(10.0),
                        indicatorBorderRadius: BorderRadius.zero,
                      ),
                      values: const [0, 1, 2],
                      iconOpacity: 1.0,
                      selectedIconScale: 1.0,
                      indicatorSize: const Size.fromWidth(100),
                      iconAnimationType: AnimationType.onHover,
                      styleAnimationType: AnimationType.onHover,
                      spacing: 2.0,
                      customSeparatorBuilder: (context, local, global) {
                        final opacity = ((global.position - local.position).abs() - 0.5).clamp(0.0, 1.0);
                        return VerticalDivider(
                            indent: 10.0,
                            endIndent: 10.0,
                            color: Colors.white38.withOpacity(opacity));
                      },
                      customIconBuilder: (context, local, global) {
                        final text = const ['not', 'only', 'icons'][local.index];
                        return Center(
                            child: Text(text,
                                style: TextStyle(
                                    color: Color.lerp(Colors.black, Colors.white, local.animationValue))));
                      },
                      borderWidth: 0.0,
                    ),
                    // 双按钮动画开关
                    ReactiveAnimatedToggleSwitchDual<bool, bool>(
                      formControlName: 'dual',
                      first: false,
                      second: true,
                      spacing: 50.0,
                      style: const ToggleStyle(
                        borderColor: Colors.transparent,
                        boxShadow: [
                          BoxShadow(
                            color: Colors.black26,
                            spreadRadius: 1,
                            blurRadius: 2,
                            offset: Offset(0, 1.5),
                          ),
                        ],
                      ),
                      borderWidth: 5.0,
                      height: 55,
                      styleBuilder: (b) => ToggleStyle(
                          indicatorColor: b ? Colors.red : Colors.green),
                      iconBuilder: (value) => value
                          ? const Icon(Icons.coronavirus_rounded)
                          : const Icon(Icons.tag_faces_rounded),
                      textBuilder: (value) => value
                          ? const Center(child: Text('Oh no...'))
                          : const Center(child: Text('Nice :)')),
                    ),
                    // 提交按钮
                    ElevatedButton(
                      child: const Text('Submit'),
                      onPressed: () {
                        if (form.valid) {
                          debugPrint(form.value.toString());
                        }
                      },
                    ),
                  ],
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}

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

1 回复

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


当然,以下是一个关于如何使用reactive_animated_toggle_switch插件的Flutter代码示例。这个插件提供了一个带有动画效果的开关组件,非常适合在用户界面中展示开关状态。

首先,确保你已经在pubspec.yaml文件中添加了reactive_animated_toggle_switch依赖:

dependencies:
  flutter:
    sdk: flutter
  reactive_animated_toggle_switch: ^2.0.0  # 请检查最新版本号

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

接下来,是一个完整的Flutter应用示例,展示了如何使用ReactiveAnimatedToggleSwitch

import 'package:flutter/material.dart';
import 'package:reactive_animated_toggle_switch/reactive_animated_toggle_switch.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => ToggleSwitchNotifier()),
      ],
      child: MaterialApp(
        title: 'Reactive Animated Toggle Switch Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(),
      ),
    );
  }
}

class ToggleSwitchNotifier with ChangeNotifier {
  bool isSwitchedOn = false;

  void toggleSwitch() {
    isSwitchedOn = !isSwitchedOn;
    notifyListeners();
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final toggleSwitchNotifier = context.watch<ToggleSwitchNotifier>();

    return Scaffold(
      appBar: AppBar(
        title: Text('Reactive Animated Toggle Switch Demo'),
      ),
      body: Center(
        child: ReactiveAnimatedToggleSwitch.multipleValues<bool>(
          values: [toggleSwitchNotifier.isSwitchedOn],
          activeColor: Colors.green,
          inactiveColor: Colors.grey,
          inactiveThumbColor: Colors.white,
          activeThumbColor: Colors.white,
          size: 50.0,
          onToggle: (index, value) {
            toggleSwitchNotifier.toggleSwitch();
          },
          labels: ReactiveToggleSwitchLabel.both(
            onLabel: Text('ON'),
            offLabel: Text('OFF'),
          ),
        ),
      ),
    ),
  );
  }
}

代码解释:

  1. 依赖注入和状态管理

    • 使用provider包来管理开关的状态。ToggleSwitchNotifier类包含一个布尔值isSwitchedOn,并提供了一个toggleSwitch方法来切换该值。
  2. UI构建

    • MyApp类设置了MaterialApp,并使用MultiProvider来提供ToggleSwitchNotifier实例。
    • MyHomePage类构建了一个简单的UI,包含一个ReactiveAnimatedToggleSwitch组件。
  3. ReactiveAnimatedToggleSwitch

    • values属性接受一个布尔值列表,这里只有一个值toggleSwitchNotifier.isSwitchedOn
    • activeColorinactiveColor分别设置开关激活和未激活时的背景颜色。
    • inactiveThumbColoractiveThumbColor设置开关拇指(滑块)的颜色。
    • size属性设置开关的大小。
    • onToggle回调在开关状态改变时被调用,这里用来调用toggleSwitchNotifiertoggleSwitch方法。
    • labels属性设置开关的标签,ReactiveToggleSwitchLabel.both方法允许同时显示“ON”和“OFF”标签。

这个示例展示了如何使用reactive_animated_toggle_switch插件来创建一个具有动画效果的开关,并结合provider包来管理开关的状态。你可以根据需要进一步自定义开关的样式和行为。

回到顶部