Flutter动画切换插件animated_toggle的使用

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

Flutter动画切换插件animated_toggle的使用

Animated Toggle

Pub Pub likes Pub popularity Pub points

P1

Animated Toggle 为您提供了一种简单的方法来创建自定义动画切换效果。

Vertical Examples Horizontal Examples Default Ex

Full Ex

安装

在您的 pubspec.yaml 文件中添加以下内容:

dependencies:
  animated_toggle: ^Last Version

功能

  • 易于使用,可以处理所有颜色、宽度和高度。
  • 可以创建垂直或水平的动画切换。
  • 支持从左到右或从右到左开始(适用于阿拉伯语或英语等)。
  • 可以控制文本样式和动画切换的填充。

使用方法

水平动画切换

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

class MyAnimatedToggle extends StatefulWidget {
  const MyAnimatedToggle({super.key});

  @override
  State<MyAnimatedToggle> createState() => _MyAnimatedToggleState();
}

class _MyAnimatedToggleState extends State<MyAnimatedToggle> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Animated Toggle'),
      ),
      body: Center(
        child: AnimatedHorizontalToggle(
          taps: const ['First', 'Second', 'Last'],
          width: MediaQuery.of(context).size.width - 40,
          height: 48,
          duration: const Duration(milliseconds: 300),
          initialIndex: 0,
          background: Colors.black.withOpacity(0.1),
          activeColor: Colors.deepPurple,
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
          horizontalPadding: 4,
          verticalPadding: 4,
          activeHorizontalPadding: 2,
          activeVerticalPadding: 4,
          radius: 14,
          activeButtonRadius: 14,
          onChange: (int currentIndex, int targetIndex) {
            // 写入您个人的代码
          },
          showActiveButtonColor: true,
          local: 'en',
        ),
      ),
    );
  }
}

垂直动画切换

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

class MyAnimatedToggle extends StatefulWidget {
  const MyAnimatedToggle({super.key});

  @override
  State<MyAnimatedToggle> createState() => _MyAnimatedToggleState();
}

class _MyAnimatedToggleState extends State<MyAnimatedToggle> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Animated Toggle'),
      ),
      body: Center(
        child: AnimatedVerticalToggle(
          taps: const ['First', 'Second', 'Third', 'Last'],
          width: 80,
          height: 200,
          duration: const Duration(milliseconds: 300),
          activeButtonHeight: 34,
          initialIndex: 0,
          background: Colors.black.withOpacity(0.1),
          activeColor: Colors.deepPurple,
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
          horizontalPadding: 4,
          verticalPadding: 4,
          activeHorizontalPadding: 4,
          activeVerticalPadding: 2,
          radius: 14,
          activeButtonRadius: 10,
          onChange: (int currentIndex, int targetIndex) {
            // 写入您个人的代码
          },
          showActiveButtonColor: true,
          local: 'en',
        ),
      ),
    );
  }
}

更多示例

以下是包含多个示例的完整代码:

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyAnimatedToggle(),
    );
  }
}

class MyAnimatedToggle extends StatefulWidget {
  const MyAnimatedToggle({super.key});

  @override
  State<MyAnimatedToggle> createState() => _MyAnimatedToggleState();
}

class _MyAnimatedToggleState extends State<MyAnimatedToggle> {
  int secondVExIndex = 0;
  int secondHExIndex = 0;
  int lastHExIndex = 0;
  int lastVExIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.deepPurple,
        title: const Text(
          'Animated Toggle',
          style: TextStyle(color: Colors.white),
        ),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 20.0),
          child: SingleChildScrollView(
            child: Column(
              children: [
                animatedHorizontalToggle(context),
                const SizedBox(height: 30),
                animatedVerticalToggle(),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Column animatedVerticalToggle() {
    return Column(
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            AnimatedVerticalToggle(
              taps: const ['First', 'Second', 'Third', 'Last'],
              width: 80,
              height: 200,
              duration: const Duration(milliseconds: 300),
              activeButtonHeight: 34,
              initialIndex: 0,
              background: Colors.black.withOpacity(0.1),
              activeColor: Colors.deepPurple,
              activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
              inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
              horizontalPadding: 4,
              verticalPadding: 4,
              activeHorizontalPadding: 4,
              activeVerticalPadding: 2,
              radius: 14,
              activeButtonRadius: 10,
              onChange: (int currentIndex, int targetIndex) {},
              showActiveButtonColor: true,
              local: 'en',
            ),
            AnimatedVerticalToggle(
              taps: const ['First', 'Second', 'Third', 'Last'],
              width: 80,
              height: 200,
              duration: const Duration(milliseconds: 300),
              activeButtonHeight: 34,
              initialIndex: 0,
              background: Colors.transparent,
              activeBorder: Border.all(color: Colors.black),
              inActiveColor: Colors.white,
              inActiveBoxShadow: [
                BoxShadow(
                  offset: const Offset(0, 2.2),
                  blurRadius: 12,
                  color: Colors.black.withOpacity(0.08),
                ),
              ],
              activeColor: Colors.deepPurple.withOpacity(0.5),
              activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
              inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
              horizontalPadding: 4,
              verticalPadding: 4,
              activeHorizontalPadding: 4,
              activeVerticalPadding: 2,
              radius: 14,
              activeButtonRadius: 10,
              inActiveButtonRadius: 10,
              onChange: (int currentIndex, int targetIndex) {},
              showActiveButtonColor: true,
              local: 'en',
            ),
            AnimatedVerticalToggle(
              taps: const ['First', 'Second', 'Last'],
              width: 105,
              height: 200,
              duration: const Duration(milliseconds: 300),
              initialIndex: 0,
              showPrefixIcon: true,
              spaceBetweenIconAndText: 8,
              prefixIcons: [
                Icon(Icons.ac_unit_rounded, color: secondVExIndex == 0 ? Colors.white : Colors.deepPurple),
                Icon(Icons.accessibility_new_rounded, color: secondVExIndex == 1 ? Colors.white : Colors.deepPurple),
                Icon(Icons.account_balance_wallet, color: secondVExIndex == 2 ? Colors.white : Colors.deepPurple),
              ],
              background: Colors.black.withOpacity(0.1),
              activeColor: Colors.deepPurple,
              activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
              inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
              horizontalPadding: 4,
              verticalPadding: 4,
              activeHorizontalPadding: 4,
              activeVerticalPadding: 2,
              radius: 14,
              activeButtonRadius: 14,
              onChange: (int currentIndex, int targetIndex) {
                setState(() {
                  secondVExIndex = currentIndex;
                });
              },
              showActiveButtonColor: true,
              local: 'en',
            ),
          ],
        ),
        const SizedBox(height: 30),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            AnimatedVerticalToggle(
              taps: const ['First', 'Second', 'Last'],
              width: 90,
              height: 200,
              duration: const Duration(milliseconds: 300),
              initialIndex: 0,
              background: Colors.transparent,
              activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.deepPurple),
              inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.black),
              horizontalPadding: 8,
              verticalPadding: 0,
              activeHorizontalPadding: 0,
              activeVerticalPadding: 0,
              radius: 14,
              activeButtonRadius: 14,
              sideLineWidth: 1,
              activeSideLineWidth: 2,
              onChange: (int currentIndex, int targetIndex) {},
              sideLineColor: Colors.black.withOpacity(0.3),
              activeSideLineColor: Colors.deepPurple,
              showSideLine: true,
              showActiveButtonColor: false,
              local: 'en',
            ),
            AnimatedVerticalToggle(
              taps: const ['First', 'Second', 'Third', 'Last'],
              width: 120,
              height: 200,
              duration: const Duration(milliseconds: 300),
              initialIndex: 0,
              showPrefixIcon: true,
              spaceBetweenIconAndText: 8,
              prefixIcons: [
                Icon(Icons.ac_unit_rounded, color: lastVExIndex == 0 ? Colors.deepPurple : Colors.black),
                Icon(Icons.accessibility_new_rounded, color: lastVExIndex == 1 ? Colors.deepPurple : Colors.black),
                Icon(Icons.account_balance_wallet, color: lastVExIndex == 2 ? Colors.deepPurple : Colors.black),
                Icon(Icons.account_balance, color: lastVExIndex == 3 ? Colors.deepPurple : Colors.black),
              ],
              background: Colors.transparent,
              activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.deepPurple),
              inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.black),
              horizontalPadding: 8,
              verticalPadding: 0,
              activeHorizontalPadding: 0,
              activeVerticalPadding: 0,
              radius: 14,
              activeButtonRadius: 14,
              sideLineWidth: 1,
              activeSideLineWidth: 2,
              onChange: (int currentIndex, int targetIndex) {
                setState(() {
                  lastVExIndex = currentIndex;
                });
              },
              sideLineColor: Colors.black.withOpacity(0.3),
              activeSideLineColor: Colors.deepPurple,
              showSideLine: true,
              showActiveButtonColor: false,
              local: 'en',
            ),
          ],
        )
      ],
    );
  }

  Widget animatedHorizontalToggle(BuildContext context) {
    return Column(
      children: [
        const SizedBox(height: 30),
        AnimatedHorizontalToggle(
          taps: const ['First', 'Second', 'Last'],
          width: MediaQuery.of(context).size.width - 40,
          height: 48,
          spaceBetween: 15,
          duration: const Duration(milliseconds: 500),
          initialIndex: 0,
          background: Colors.transparent,
          activeBorder: Border.all(color: Colors.black),
          inActiveColor: Colors.white,
          inActiveBoxShadow: [
            BoxShadow(
              offset: const Offset(0, 2.2),
              blurRadius: 12,
              color: Colors.black.withOpacity(0.08),
            ),
          ],
          activeColor: Colors.deepPurple.withOpacity(0.5),
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
          horizontalPadding: 0,
          verticalPadding: 0,
          activeHorizontalPadding: 0,
          activeVerticalPadding: 0,
          radius: 14,
          activeButtonRadius: 14,
          inActiveButtonRadius: 14,
          onChange: (int currentIndex, int targetIndex) {},
          showActiveButtonColor: true,
          local: 'en',
        ),
        const SizedBox(height: 30),
        AnimatedHorizontalToggle(
          taps: const ['First', 'Second', 'Last'],
          width: MediaQuery.of(context).size.width - 40,
          height: 48,
          duration: const Duration(milliseconds: 300),
          initialIndex: 0,
          background: Colors.black.withOpacity(0.1),
          activeColor: Colors.deepPurple,
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
          horizontalPadding: 4,
          verticalPadding: 4,
          activeHorizontalPadding: 2,
          activeVerticalPadding: 4,
          radius: 14,
          activeButtonRadius: 14,
          onChange: (int currentIndex, int targetIndex) {},
          showActiveButtonColor: true,
          local: 'en',
        ),
        const SizedBox(height: 30),
        AnimatedHorizontalToggle(
          taps: const ['First', 'Second', 'Last'],
          width: MediaQuery.of(context).size.width - 40,
          height: 48,
          duration: const Duration(milliseconds: 300),
          initialIndex: 0,
          showPrefixIcon: true,
          spaceBetweenIconAndText: 8,
          prefixIcons: [
            Icon(Icons.ac_unit_rounded, color: secondHExIndex == 0 ? Colors.white : Colors.deepPurple),
            Icon(Icons.accessibility_new_rounded, color: secondHExIndex == 1 ? Colors.white : Colors.deepPurple),
            Icon(Icons.account_balance_wallet, color: secondHExIndex == 2 ? Colors.white : Colors.deepPurple),
          ],
          background: Colors.black.withOpacity(0.1),
          activeColor: Colors.deepPurple,
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.deepPurple),
          horizontalPadding: 4,
          verticalPadding: 4,
          activeHorizontalPadding: 2,
          activeVerticalPadding: 4,
          radius: 14,
          activeButtonRadius: 14,
          onChange: (int currentIndex, int targetIndex) {
            setState(() {
              secondHExIndex = currentIndex;
            });
          },
          showActiveButtonColor: true,
          local: 'en',
        ),
        const SizedBox(height: 30),
        AnimatedHorizontalToggle(
          taps: const ['First', 'Second', 'Last'],
          width: MediaQuery.of(context).size.width - 40,
          height: 48,
          duration: const Duration(milliseconds: 300),
          initialIndex: 0,
          background: Colors.transparent,
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.deepPurple),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.black),
          horizontalPadding: 0,
          verticalPadding: 0,
          activeHorizontalPadding: 0,
          activeVerticalPadding: 0,
          radius: 14,
          activeButtonRadius: 14,
          underLineHeight: 1,
          activeUnderLineHeight: 2,
          onChange: (int currentIndex, int targetIndex) {},
          underLineColor: Colors.black.withOpacity(0.3),
          activeUnderLineColor: Colors.deepPurple,
          showUnderLine: true,
          showActiveButtonColor: false,
          local: 'en',
        ),
        const SizedBox(height: 30),
        AnimatedHorizontalToggle(
          taps: const ['First', 'Second', 'Last'],
          width: MediaQuery.of(context).size.width - 40,
          height: 48,
          duration: const Duration(milliseconds: 300),
          initialIndex: 0,
          showPrefixIcon: true,
          spaceBetweenIconAndText: 8,
          prefixIcons: [
            Icon(Icons.ac_unit_rounded, color: lastHExIndex == 0 ? Colors.deepPurple : Colors.black),
            Icon(Icons.accessibility_new_rounded, color: lastHExIndex == 1 ? Colors.deepPurple : Colors.black),
            Icon(Icons.account_balance_wallet, color: lastHExIndex == 2 ? Colors.deepPurple : Colors.black),
          ],
          background: Colors.transparent,
          activeTextStyle: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.deepPurple),
          inActiveTextStyle: const TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.black),
          horizontalPadding: 0,
          verticalPadding: 0,
          activeHorizontalPadding: 0,
          activeVerticalPadding: 0,
          radius: 14,
          activeButtonRadius: 14,
          underLineHeight: 1,
          activeUnderLineHeight: 2,
          onChange: (int currentIndex, int targetIndex) {
            setState(() {
              lastHExIndex = currentIndex;
            });
          },
          underLineColor: Colors.black.withOpacity(0.3),
          activeUnderLineColor: Colors.deepPurple,
          showUnderLine: true,
          showActiveButtonColor: false,
          local: 'en',
        ),
      ],
    );
  }
}

额外信息

如果您有任何需求或建议,请在GitHub上告诉我。期待更多功能的更新!

作者

Loay Omar


希望这个详细的说明和示例代码能帮助您更好地理解和使用 animated_toggle 插件。如果有任何问题,欢迎随时提问!


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

1 回复

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


当然,下面是一个关于如何在Flutter中使用animated_toggle插件来实现动画切换的示例代码。animated_toggle是一个用于创建具有动画效果的切换按钮的Flutter插件。

首先,确保你已经将animated_toggle插件添加到了你的pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  animated_toggle: ^x.y.z  # 请将x.y.z替换为最新版本号

然后,你可以在你的Flutter项目中这样使用它:

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

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

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

class ToggleScreen extends StatefulWidget {
  @override
  _ToggleScreenState createState() => _ToggleScreenState();
}

class _ToggleScreenState extends State<ToggleScreen> with SingleTickerProviderStateMixin {
  bool isToggled = false;

  void toggle() {
    setState(() {
      isToggled = !isToggled;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Animated Toggle Demo'),
      ),
      body: Center(
        child: AnimatedToggle(
          value: isToggled,
          onToggle: toggle,
          width: 100,
          height: 50,
          thumbColor: isToggled ? Colors.green : Colors.red,
          trackColor: isToggled ? Colors.lightGreen : Colors.grey,
          thumbInactiveIcon: Icon(Icons.thumb_down),
          thumbActiveIcon: Icon(Icons.thumb_up),
          animationDuration: Duration(milliseconds: 300),
        ),
      ),
    );
  }
}

代码解释:

  1. 导入依赖

    • import 'package:flutter/material.dart';:导入Flutter的核心Material组件。
    • import 'package:animated_toggle/animated_toggle.dart';:导入animated_toggle插件。
  2. 主应用入口

    • MyApp类是一个无状态的Widget,它定义了应用的主题和主页。
  3. 主页

    • ToggleScreen是一个有状态的Widget,它管理切换按钮的状态。
    • _ToggleScreenStateToggleScreen的状态类,它包含了一个布尔值isToggled来跟踪切换按钮的状态。
  4. 切换按钮

    • AnimatedToggle是一个自定义的切换按钮组件,它接收多个参数:
      • value:当前按钮的状态(开或关)。
      • onToggle:当按钮被切换时调用的回调函数。
      • widthheight:按钮的宽度和高度。
      • thumbColortrackColor:按钮滑块和轨道的颜色。
      • thumbInactiveIconthumbActiveIcon:按钮在关闭和打开状态下的图标。
      • animationDuration:动画的持续时间。

运行这个示例代码,你将看到一个带有动画效果的切换按钮,点击按钮时,它会改变颜色和图标,并且有一个平滑的动画过渡效果。

回到顶部