0

嗨,

我是飞镖和颤振的新手,因此为什么你会发现我的代码很乱(我真的不知道什么时候使用类和小部件)。

我正在尝试使用来自资产的图像生成可点击的卡片,这些卡片在点击时会转身 - 问题是它们作为一个,当点击一个时它们都会转动。当我第二次点击时,什么也没有发生。

在这里它显示了它的作用

import 'dart:typed_data';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'assetsLists.dart';
import 'dart:math';

// AudioPlayer player = AudioPlayer();

void main() => runApp(const MaterialApp(
      home: Home(),
    ));

class Home extends StatefulWidget {
  const Home({Key? key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {

  AudioPlayer player = AudioPlayer();
  bool isFront = true;
  double angle = 0;

  void _flip() {
    setState(() {
      angle = (angle + pi) % (2 * pi);
    });
    if(isFront) {
      isFront = false;
    }
    else {
      isFront = true;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("tap card to play a sound"),
        centerTitle: true,
        elevation: 5.0,
        backgroundColor: Colors.green,
      ),
      body: Padding(
          padding: const EdgeInsets.fromLTRB(10, 12, 10, 12),
          child: cardGridBuilder()),
    );
  }

  Widget cardGridBuilder() => GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
        padding: const EdgeInsets.fromLTRB(5, 5, 5, 5),
        itemCount: cardAssets.length,
        itemBuilder: (context, index) {
          return cardBuilder(index);
          
          },
  );

  Widget cardBuilder(int number) {
    return Container(
      child: GestureDetector(
        onTap: _flip,
        child: Center(
          child: TweenAnimationBuilder(
                  tween: Tween<double>(begin: 0, end: angle),
                  duration: Duration(milliseconds: 500),
                  builder: (BuildContext context, double val, __) {
                    String pictureAsset = cardAssets[number][0];
                    String soundAsset = cardAssets[number][1];
                    return (Transform(
                      transform: Matrix4.identity()
                        ..setEntry(3, 2, 0.001)
                        ..rotateY(val),
                      child: Container(
                        width: 200,
                        height: 350,
                        child: isFront 
                        ? Container(
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image: AssetImage('assets/Images/$pictureAsset')
                              )
                            )
                          )
                        : Container(
                            decoration: BoxDecoration(
                              image: DecorationImage(
                                image: AssetImage('assets/Images/$pictureAsset')
                              )
                            )
                          )
      
                          // String audioasset = 'assets/Sounds/$soundAsset';
                          // ByteData bytes = await rootBundle.load(audioasset); //load sound from assets
                          // Uint8List soundbytes = bytes.buffer.asUint8List(bytes.offsetInBytes, bytes.lengthInBytes);
                          // int result = await player.playBytes(soundbytes);
                          
                      )
                      )
                    );
                  }
                ),
        ),
      )
    );
  }
}

现在我只有几个样本,但最后会有 104 个:

List<List<String>> cardAssets = [
  ['IceWizardCard.webp','IceWizardSound.mp3','6'],
  ['MegaKnightCard.webp','MegaKnightSound.mp3','6'],
  ['WizardCard.webp','WizardSound.mp3', '4'],
];

我知道映射功能,但我选择了gridview builder,因为我有一个数组数组,其中保存了资产地址。也不要介意注释代码,它用于在特定卡上播放特定音频。

我谢谢大家!

4

1 回答 1

0

要专门为点击的网格单元设置动画,您可以使用GridView.builder 提供的index 参数。

例如,当用户点击给定单元格时,该单元格的索引可以保存在局部变量中,然后触发状态更新。并使用此值作为构建器提供的索引的条件。

然后动画控制器将仅在此条件为真时运行(下面的示例提供了更清晰的说明)。

另外:**我已更新以将动画逻辑分离到一个单独的类中,我建议对小部件进行整理。

**我在本例中使用 setState(){} 方法进行状态管理,但是,我建议您研究其他选项(有很多好的包)。一种流行的解决方案是Provider

**最后,说到你的第一点——一般来说,Flutter 中的小部件只是类。

我希望这可以帮助你!快乐飘飘。

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

class CardTurnExample extends StatefulWidget {
  const CardTurnExample({Key? key}) : super(key: key);

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

class _CardTurnExampleState extends State<CardTurnExample> {
  /// [_index] temporarily holds the index that is tapped (set by [GestureDetector]).
  int? _index;

  @override
  Widget build(BuildContext context) {
    return Material(
      child: GridView.builder(
          gridDelegate:
              SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
          itemBuilder: (context, index) {
            return GestureDetector(
              onTap: () {
                _index = index;

                /// Important to call setState(){} here

                setState(() {});
              },
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: TurnAnimation(
                  runAnimation: _index == index,
                  child: Container(
                    color: Colors.red,
                    child: Center(child: Text(index.toString())),
                  ),
                ),
              ),
            );
          }),
    );
  }
}

/// Animation is separated into its own class for clarity.
/// It also means this logic can also be reused easily in your app.
class TurnAnimation extends StatefulWidget {
  const TurnAnimation(
      {required this.child, required this.runAnimation, Key? key})
      : super(key: key);

  final Widget child;
  final bool runAnimation;

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

class _TurnAnimationState extends State<TurnAnimation>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    _controller =
        AnimationController(duration: Duration(milliseconds: 500), vsync: this);
    super.initState();
  }

  /// Important to set the [Controller.forward] in it's own local method, so it only runs
  /// when the passed in boolean is true
  _runAnimation() {
    if (widget.runAnimation) {
      _controller.forward();
    }
  }

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

  @override
  Widget build(BuildContext context) {
    _runAnimation();
    return AnimatedBuilder(
      animation: _controller,
      builder: (_, child) => Transform(
        alignment: Alignment.center,
        transform: Matrix4.identity()
          ..setEntry(3, 2, 0.001)
          ..rotateY(_controller.value * pi),
        child: widget.child,
      ),
    );
  }
}


在此处输入图像描述

例子

于 2022-02-05T07:07:36.297 回答