Skip to content

Instantly share code, notes, and snippets.

@johnpryan
Last active November 19, 2019 18:47
Show Gist options
  • Save johnpryan/b70710dde62f636bccfec5a1cfaa6bc4 to your computer and use it in GitHub Desktop.
Save johnpryan/b70710dde62f636bccfec5a1cfaa6bc4 to your computer and use it in GitHub Desktop.
Sliding Square
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