Last active
November 19, 2019 18:47
-
-
Save johnpryan/b70710dde62f636bccfec5a1cfaa6bc4 to your computer and use it in GitHub Desktop.
Sliding Square
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter_web/material.dart'; | |
import 'package:flutter_web_test/flutter_web_test.dart'; | |
import 'package:flutter_web_ui/ui.dart' as ui; | |
Future main() async { | |
await ui.webOnlyInitializePlatform(); | |
runApp(MaterialApp( | |
debugShowCheckedModeBanner: false, | |
home: AnimatedAlignDemo(), | |
theme: ThemeData.dark(), | |
)); | |
} | |
class AnimatedAlignDemo extends StatelessWidget { | |
Widget build(BuildContext context) { | |
return Scaffold( | |
body: Center( | |
child: AspectRatio( | |
aspectRatio: 1, | |
child: Padding( | |
padding: const EdgeInsets.all(16.0), | |
child: SlidePuzzle( | |
boardSize: 5, | |
), | |
), | |
), | |
), | |
); | |
} | |
} | |
class SlidePuzzle extends StatefulWidget { | |
final Duration duration = Duration(milliseconds: 200); | |
final int boardSize; | |
SlidePuzzle({this.boardSize = 5}); | |
_SlidePuzzleState createState() => _SlidePuzzleState(); | |
} | |
class _SlidePuzzleState extends State<SlidePuzzle> { | |
int row; | |
int col; | |
void initState() { | |
row = widget.boardSize ~/ 2; | |
col = widget.boardSize ~/ 2; | |
super.initState(); | |
} | |
List<AnimatedTile> get tiles => [ | |
AnimatedTile( | |
boardSize: widget.boardSize, | |
row: row, | |
col: col, | |
child: Tile(), | |
duration: widget.duration, | |
), | |
]; | |
void _moveTileLeft() => row = (row - 1) % widget.boardSize; | |
void _moveTileUp() => col = (col - 1) % widget.boardSize; | |
void _moveTileRight() => row = (row + 1) % widget.boardSize; | |
void _moveTileDown() => col = (col + 1) % widget.boardSize; | |
Widget build(BuildContext context) { | |
return SwipeDetector( | |
onSwipeUp: () => setState(() => _moveTileUp()), | |
onSwipeDown: () => setState(() => _moveTileDown()), | |
onSwipeLeft: () => setState(() => _moveTileLeft()), | |
onSwipeRight: () => setState(() => _moveTileRight()), | |
child: Container( | |
child: Stack( | |
children: tiles, | |
), | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(4.0), | |
color: Colors.grey.shade700, | |
), | |
), | |
); | |
} | |
} | |
class Tile extends StatelessWidget { | |
const Tile({ | |
Key key, | |
}) : super(key: key); | |
Widget build(BuildContext context) { | |
return Padding( | |
padding: const EdgeInsets.all(4.0), | |
child: DecoratedBox( | |
decoration: BoxDecoration( | |
borderRadius: BorderRadius.circular(4.0), | |
color: Colors.deepOrange, | |
), | |
child: Center( | |
child: Text('Slide me!', style: TextStyle(color: Colors.white)), | |
), | |
), | |
); | |
} | |
} | |
class AnimatedTile extends StatelessWidget { | |
final int boardSize; | |
final int row; | |
final int col; | |
final Widget child; | |
final Duration duration; | |
AnimatedTile({ | |
this.boardSize, | |
this.row, | |
this.col, | |
this.child, | |
this.duration, | |
}); | |
AlignmentGeometry get alignment { | |
var maxTileIndex = (boardSize - 1).toDouble(); | |
var rowPosition = ui.lerpDouble(-1.0, 1.0, row.toDouble() / maxTileIndex); | |
var colPosition = ui.lerpDouble(-1.0, 1.0, col.toDouble() / maxTileIndex); | |
return Alignment(rowPosition, colPosition); | |
} | |
Widget build(BuildContext context) { | |
return AnimatedAlign( | |
alignment: alignment, | |
duration: duration, | |
curve: Curves.ease, | |
child: FractionallySizedBox( | |
widthFactor: 1.0 / boardSize, | |
heightFactor: 1.0 / boardSize, | |
child: child, | |
), | |
); | |
} | |
} | |
class SwipeDetector extends StatefulWidget { | |
final Widget child; | |
final VoidCallback onSwipeLeft; | |
final VoidCallback onSwipeUp; | |
final VoidCallback onSwipeRight; | |
final VoidCallback onSwipeDown; | |
SwipeDetector({ | |
this.child, | |
this.onSwipeLeft, | |
this.onSwipeUp, | |
this.onSwipeRight, | |
this.onSwipeDown, | |
}); | |
_SwipeDetectorState createState() => _SwipeDetectorState(); | |
} | |
class _SwipeDetectorState extends State<SwipeDetector> { | |
double _verticalStartY = 0.0; | |
double _verticalEndY = 0.0; | |
double _verticalDrag = 0.0; | |
double _horizontalStartX = 0.0; | |
double _horizontalEndX = 0.0; | |
double _horizontalDrag = 0.0; | |
_horizontalStart(DragStartDetails details) { | |
if (details == null || details.globalPosition == null) return; | |
_horizontalStartX = details.globalPosition.dx; | |
} | |
_horizontalUpdate(DragUpdateDetails details) { | |
if (details == null || details.globalPosition == null) { | |
return; | |
} | |
_horizontalEndX = details.globalPosition.dx; | |
var distance = _horizontalEndX - _horizontalStartX; | |
if (distance != null && distance < 0 && _horizontalDrag < 0 || | |
distance > 0 && _horizontalDrag > 0) { | |
return; | |
} | |
if (distance < 0) { | |
widget.onSwipeLeft(); | |
} else if (distance > 0) { | |
widget.onSwipeRight(); | |
} | |
_horizontalDrag = distance; | |
} | |
_horizontalEnd(DragEndDetails details) { | |
_horizontalDrag = 0.0; | |
} | |
_verticalStart(DragStartDetails details) { | |
if (details == null || details.globalPosition == null) return; | |
_verticalStartY = details.globalPosition.dy; | |
} | |
_verticalUpdate(DragUpdateDetails details) { | |
if (details == null || details.globalPosition == null) { | |
return; | |
} | |
_verticalEndY = details.globalPosition.dy; | |
var distance = _verticalEndY - _verticalStartY; | |
if (distance != null && distance < 0 && _verticalDrag < 0 || | |
distance > 0 && _verticalDrag > 0) { | |
return; | |
} | |
if (distance < 0) { | |
widget.onSwipeUp(); | |
} else if (distance > 0) { | |
widget.onSwipeDown(); | |
} | |
_verticalDrag = distance; | |
} | |
_verticalEnd(DragEndDetails details) { | |
_verticalDrag = 0.0; | |
} | |
Widget build(BuildContext context) { | |
return GestureDetector( | |
onHorizontalDragStart: _horizontalStart, | |
onHorizontalDragUpdate: _horizontalUpdate, | |
onHorizontalDragEnd: _horizontalEnd, | |
onVerticalDragStart: _verticalStart, | |
onVerticalDragUpdate: _verticalUpdate, | |
onVerticalDragEnd: _verticalEnd, | |
child: widget.child, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment