Skip to content

Commit

Permalink
Pan and zoom gallery demo (flutter#25164)
Browse files Browse the repository at this point in the history
Adds the "2D Transformations" demo to the gallery, which shows how to do things such as navigate around a map a la Google Maps, or show a full screen zoomable photo.  The idea is to abstract this code into a first class widget soon.
  • Loading branch information
justinmc authored Apr 4, 2019
1 parent 423cf22 commit 3ada502
Show file tree
Hide file tree
Showing 8 changed files with 1,191 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/flutter_gallery/lib/demo/all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export 'images_demo.dart';
export 'material/material.dart';
export 'pesto_demo.dart';
export 'shrine_demo.dart';
export 'transformations/transformations_demo.dart';
export 'typography_demo.dart';
export 'video_demo.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import 'dart:ui' show Vertices;
import 'package:flutter/material.dart';
import 'transformations_demo_board.dart';
import 'transformations_demo_edit_board_point.dart';
import 'transformations_demo_gesture_transformable.dart';

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

static const String routeName = '/transformations';

@override _TransformationsDemoState createState() => _TransformationsDemoState();
}
class _TransformationsDemoState extends State<TransformationsDemo> {
// The radius of a hexagon tile in pixels.
static const double _kHexagonRadius = 32.0;
// The margin between hexagons.
static const double _kHexagonMargin = 1.0;
// The radius of the entire board in hexagons, not including the center.
static const int _kBoardRadius = 8;

bool _reset = false;
Board _board = Board(
boardRadius: _kBoardRadius,
hexagonRadius: _kHexagonRadius,
hexagonMargin: _kHexagonMargin,
);

@override
Widget build (BuildContext context) {
final BoardPainter painter = BoardPainter(
board: _board,
);

// The scene is drawn by a CustomPaint, but user interaction is handled by
// the GestureTransformable parent widget.
return Scaffold(
appBar: AppBar(),
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
// Draw the scene as big as is available, but allow the user to
// translate beyond that to a visibleSize that's a bit bigger.
final Size size = Size(constraints.maxWidth, constraints.maxHeight);
final Size visibleSize = Size(size.width * 3, size.height * 2);
return GestureTransformable(
reset: _reset,
onResetEnd: () {
setState(() {
_reset = false;
});
},
child: CustomPaint(
painter: painter,
),
boundaryRect: Rect.fromLTWH(
-visibleSize.width / 2,
-visibleSize.height / 2,
visibleSize.width,
visibleSize.height,
),
// Center the board in the middle of the screen. It's drawn centered
// at the origin, which is the top left corner of the
// GestureTransformable.
initialTranslation: Offset(size.width / 2, size.height / 2),
onTapUp: _onTapUp,
size: size,
);
},
),
floatingActionButton: _board.selected == null ? resetButton : editButton,
);
}

FloatingActionButton get resetButton {
return FloatingActionButton(
onPressed: () {
setState(() {
_reset = true;
});
},
tooltip: 'Reset Transform',
backgroundColor: Theme.of(context).primaryColor,
child: const Icon(Icons.home),
);
}

FloatingActionButton get editButton {
return FloatingActionButton(
onPressed: () {
if (_board.selected == null) {
return;
}
showModalBottomSheet<Widget>(context: context, builder: (BuildContext context) {
return Container(
width: double.infinity,
height: 150,
padding: const EdgeInsets.all(12.0),
child: EditBoardPoint(
boardPoint: _board.selected,
onColorSelection: (Color color) {
setState(() {
_board = _board.copyWithBoardPointColor(_board.selected, color);
Navigator.pop(context);
});
},
),
);
});
},
tooltip: 'Edit Tile',
child: const Icon(Icons.edit),
);
}

void _onTapUp(TapUpDetails details) {
final Offset scenePoint = details.globalPosition;
final BoardPoint boardPoint = _board.pointToBoardPoint(scenePoint);
setState(() {
_board = _board.copyWithSelected(boardPoint);
});
}
}

// CustomPainter is what is passed to CustomPaint and actually draws the scene
// when its `paint` method is called.
class BoardPainter extends CustomPainter {
const BoardPainter({
this.board,
});

final Board board;

@override
void paint(Canvas canvas, Size size) {
void drawBoardPoint(BoardPoint boardPoint) {
final Color color = boardPoint.color.withOpacity(
board.selected == boardPoint ? 0.2 : 1.0,
);
final Vertices vertices = board.getVerticesForBoardPoint(boardPoint, color);
canvas.drawVertices(vertices, BlendMode.color, Paint());
}

board.forEach(drawBoardPoint);
}

// We should repaint whenever the board changes, such as board.selected.
@override
bool shouldRepaint(BoardPainter oldDelegate) {
return oldDelegate.board != board;
}
}
Loading

0 comments on commit 3ada502

Please sign in to comment.