📜  在点击时颤动切换色卡 - Dart (1)

📅  最后修改于: 2023-12-03 15:08:04.017000             🧑  作者: Mango

在点击时颤动切换色卡 - Dart

你是否曾经在设计用户界面时遇到过这样的需求:当用户单击一个颜色卡片时,在颤动(或 "震动")动画中显示它的选中状态,以便用户直观地了解自己的选择?

在这篇文章中,我们将介绍如何使用 Dart 编写一个简单的程序,以实现在点击时颤动切换色卡的功能。

步骤
  1. 首先,我们需要定义一个 ColorCard Widget,该 Widget 包含在点击时切换颜色卡片状态的逻辑。在 ColorCard 内部,我们可以使用 Flutter 动画库中的 AnimatedContainer Widget 和 GestureDetector Widget 来实现这个功能。
import 'package:flutter/material.dart';

class ColorCard extends StatefulWidget {
  final Color color;
  final bool isSelected;

  ColorCard({Key key, this.color, this.isSelected}) : super(key: key);

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

class _ColorCardState extends State<ColorCard>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;

  bool _isCardSelected;

  @override
  void initState() {
    super.initState();
    _isCardSelected = widget.isSelected;
    _controller = AnimationController(
      duration: const Duration(milliseconds: 75),
      vsync: this,
    );
    _animation = Tween<double>(begin: 1, end: 0.8).animate(_controller);
  }

  @override
  void didUpdateWidget(ColorCard oldWidget) {
    super.didUpdateWidget(oldWidget);
    _isCardSelected = widget.isSelected;
  }

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

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) {
        _controller.forward();
      },
      onTapUp: (_) {
        _controller.reverse();
        setState(() {
          _isCardSelected = !_isCardSelected;
        });
      },
      onTapCancel: () {
        _controller.reverse();
      },
      child: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
          color: widget.color,
          borderRadius: BorderRadius.circular(16),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.2),
              blurRadius: 10,
              offset: Offset(0, 5),
            ),
          ],
        ),
        child: Stack(
          children: [
            Positioned(
              top: 16,
              left: 16,
              child: Text(
                widget.color.toString(),
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 12,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            if (_isCardSelected)
              Center(
                child: ScaleTransition(
                  scale: _animation,
                  child: Icon(
                    Icons.check,
                    color: Colors.white,
                    size: 32,
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

上面的代码中,我们定义了一个 ColorCard Widget,它接受一个 color 参数和一个 isSelected 参数作为输入。 isSelected 参数确定颜色卡片是否处于选中状态。在 _ColorCardState 中,我们定义了 _controller_animation 变量来控制点击事件时颤动动画的实现。_isCardSelected 变量记录着颜色卡片的当前选中状态,并在点击事件中进行了更改。

build() 方法中,我们使用 GestureDetector Widget 来包装 Container Widget,以便监听点击事件。我们将 onTapDown 回调函数设置为在用户按下颜色卡片时启动颤动动画,而将 onTapUp 回调函数设置为在用户松开颜色卡片时停止动画并切换颜色卡片状态。我们还在 Stack Widget 中嵌套了一个 ScaleTransition Widget 来实现颤动动画,并使用 if 语句来根据 _isCardSelected 变量的值决定是否显示选中状态的 Icon

  1. 接下来,我们将 ColorCard Widget 添加到一个 GridView Widget 中,以便显示多个颜色卡片。我们可以通过 GestureDetector Widget 的 onTapDown 回调函数来通知父 Widget 子 Widget 点击事件已经发生。在 GridView 中添加 ShakeSwitchColorCardBehaviour Widget 来处理颤动逻辑。

以下是完整的代码:

import 'package:flutter/material.dart';

class ShakeSwitchColorCardBehaviour extends StatefulWidget {
  final List<Color> initialColors;
  final ValueChanged<int> onSelectedIndexChanged;

  ShakeSwitchColorCardBehaviour({
    Key key,
    this.initialColors = const [],
    this.onSelectedIndexChanged,
  }) : super(key: key);

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

class _ShakeSwitchColorCardBehaviourState
    extends State<ShakeSwitchColorCardBehaviour> {
  int _selectedColorIndex = -1;

  @override
  void initState() {
    super.initState();
    _selectedColorIndex = widget.initialColors.length > 0 ? 0 : -1;
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 2,
      children: List.generate(
        widget.initialColors.length,
        (index) => GestureDetector(
          onTapDown: (_) {
            setState(() {
              _selectedColorIndex = index;
            });
          },
          child: ColorCard(
            color: widget.initialColors[index],
            isSelected: _selectedColorIndex == index,
          ),
        ),
      ),
    );
  }
}

class ColorCard extends StatefulWidget {
  final Color color;
  final bool isSelected;

  ColorCard({Key key, this.color, this.isSelected}) : super(key: key);

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

class _ColorCardState extends State<ColorCard>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;

  bool _isCardSelected;

  @override
  void initState() {
    super.initState();
    _isCardSelected = widget.isSelected;
    _controller = AnimationController(
      duration: const Duration(milliseconds: 75),
      vsync: this,
    );
    _animation = Tween<double>(begin: 1, end: 0.8).animate(_controller);
  }

  @override
  void didUpdateWidget(ColorCard oldWidget) {
    super.didUpdateWidget(oldWidget);
    _isCardSelected = widget.isSelected;
  }

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

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) {
        _controller.forward();
      },
      onTapUp: (_) {
        _controller.reverse();
        setState(() {
          _isCardSelected = !_isCardSelected;
        });
      },
      onTapCancel: () {
        _controller.reverse();
      },
      child: Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(
          color: widget.color,
          borderRadius: BorderRadius.circular(16),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.2),
              blurRadius: 10,
              offset: Offset(0, 5),
            ),
          ],
        ),
        child: Stack(
          children: [
            Positioned(
              top: 16,
              left: 16,
              child: Text(
                widget.color.toString(),
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 12,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            if (_isCardSelected)
              Center(
                child: ScaleTransition(
                  scale: _animation,
                  child: Icon(
                    Icons.check,
                    color: Colors.white,
                    size: 32,
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}
结论

在这篇文章中,我们介绍了如何使用 Dart 编写一个简单的程序,以实现在点击时颤动切换色卡的功能。请根据您的实际需求进行更改和修改。