forked from flutter/flutter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pan and zoom gallery demo (flutter#25164)
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
Showing
8 changed files
with
1,191 additions
and
0 deletions.
There are no files selected for viewing
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
151 changes: 151 additions & 0 deletions
151
examples/flutter_gallery/lib/demo/transformations/transformations_demo.dart
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
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; | ||
} | ||
} |
Oops, something went wrong.