0

我正在寻找一种在页面上移动块的方法,并且,如果我与另一个块重叠,第二个应该以另一种方式移动。

在我的示例中,我有一个游戏板(6*6 块)并在一些偏移量上用一些块(块)初始化它。

我认为将所有部分都作为独立的可拖动小部件并将游戏板作为控制器来管理游戏状态应该是一个好主意。

所以,当我拖动一个块时,它会调用一个游戏板函数来检查是否有一个侧块并将其移动到另一个方向。

但无论我尝试什么,它都不起作用,因为由于手势管理,每个块都有自己的 setState(),如果我在 GameBoard 上运行 setState(),正在进行的手势被杀死,因为所有块都被重绘...

有没有好的方法来实现这一点?

谢谢 !

我的片段(使用外部库“package:align_positioned/align_positioned.dart”):

import 'dart:math';

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

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
          appBar: AppBar(title: Center(child: Text('Flutter Demo'))),
          body: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                GameBoard(),
                Padding(
                    padding: EdgeInsets.only(bottom: 4),
                    child: SizedBox(
                        height: 64,
                        width: double.infinity,
                        child: Container(
                            margin: EdgeInsets.all(8),
                            decoration: BoxDecoration(
                                border: Border.all(
                                    color: Colors.white.withOpacity(0.2)),
                                borderRadius: BorderRadius.circular(8)),
                            child: MaterialButton(
                                color: Colors.grey.withOpacity(0.2),
                                onPressed: () {},
                                child: Text('start')))))
              ])),
    );
  }
}

class GameBoard extends StatefulWidget {
  GameBoard({Key key}) : super(key: key);

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

class _GameBoardState extends State<GameBoard> {
  List<GamePiece> pieces = [];

  void pieceMoveInProgress(Offset offset, String direction, double delta) {
    GamePiece sidePiece;
    if (direction == 'left') {
      sidePiece = getPiece(offset.dx - 1, offset.dy);
    } else {
      sidePiece = getPiece(offset.dx + 1, offset.dy);
    }
    if (sidePiece != null) {
      // sidePiece.move(delta * -1);
      // How to move sidePiece ? failed to find a way that works with "setState" too...
    }
  }

  GamePiece getPiece(double x, double y) {
    for (var piece in this.pieces) {
      if (piece.x == x && piece.y == y) {
        return piece;
      }
    }
    return null;
  }

  @override
  void initState() {
    super.initState();
    pieces = [
      GamePiece(x: 0.0, y: 0.0, moveInProgress: pieceMoveInProgress),
      GamePiece(x: 1.0, y: 1.0, moveInProgress: pieceMoveInProgress),
      GamePiece(x: 1.0, y: 2.0, moveInProgress: pieceMoveInProgress),
      GamePiece(x: 6.0, y: 2.0, moveInProgress: pieceMoveInProgress),
      GamePiece(x: 5.0, y: 2.0, moveInProgress: pieceMoveInProgress),
    ];
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    double root = size.width;

    return Expanded(
        child: AspectRatio(
            aspectRatio: 1 / 1,
            child: Center(
                child: Container(
                    margin: EdgeInsets.all(8),
                    decoration: BoxDecoration(
                        border: Border.all(
                            color: Colors.cyan.withOpacity(0.4), width: 1),
                        borderRadius: BorderRadius.circular(24)),
                    width: root,
                    height: root,
                    child: Container(
                        child: Stack(key: UniqueKey(), children: pieces))))));
  }
}

class GamePiece extends StatefulWidget {
  final double x;
  final double y;
  final moveInProgress;

  GamePiece({Key key, this.x, this.y, this.moveInProgress})
      : super(key: key);

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

class _GamePieceState extends State<GamePiece> {
  double x;
  double y;
  double _dragStart;
  double currentX = 0.0;

  void initState() {
    super.initState();
    this.x = widget.x;
    this.y = widget.y;
    this.currentX = 0.0;
  }

  void onPanDown(DragDownDetails details) {
    _dragStart = details.localPosition.dx;
  }

  void onPanUpdate(DragUpdateDetails details, double elementSize) {
    final double minDelta = x > 0 ? elementSize * -1 : 0;
    final double maxDelta = x < 6 ? elementSize : 0;
    final double globalDelta =
        min(maxDelta, max(minDelta, details.localPosition.dx - _dragStart));

    if (globalDelta != this.currentX) {
      setState(() {
        this.currentX = globalDelta;
      });
      final String direction = globalDelta > 0 ? 'right' : 'left';
      widget.moveInProgress(Offset(x, y), direction, globalDelta);
    }
    // should event emit move((x, y), direction) when drag end
  }

  Widget build(BuildContext context) {
    return AlignPositioned(
        alignment: FractionalOffset(x / 6, y / 6),
        dx: this.currentX,
        child: Container(
            child: FractionallySizedBox(
          widthFactor: 1 / 7,
          heightFactor: 1 / 7,
          child: new LayoutBuilder(
              builder: (BuildContext context, BoxConstraints constraints) {
            return GestureDetector(
                onPanDown: onPanDown,
                onPanUpdate: (details) {
                  onPanUpdate(details, constraints.maxWidth);
                },
                child: Container(
                    padding: EdgeInsets.all(3),
                    decoration: BoxDecoration(
                        color: Colors.red.withOpacity(0.5),
                        border: Border.all(color: Colors.red, width: 1),
                        borderRadius:
                            BorderRadius.circular(constraints.maxWidth / 2))));
          }),
        )));
  }
}
4

0 回答 0