Skip to content

Commit

Permalink
WIP: Gestures update - two finger rotation / interactions filter / ma…
Browse files Browse the repository at this point in the history
…p events (#719)

* Add two finger rotation support

* Add InteractiveFlags

* Add example page

* Emit MapEvents basic

* Update interactive test page

* update interactive page

* Emit move / rotate events

* Emit rotation events

* Rotate only when rotationThreshold reached

* Update examples

* add some document

* fix some event's source

* typo fix

* Call onRotationChanged correctly

* Fix arbitrary jumps when map is panned in rotated state

* tap / longPress / double tap use rotated offset / fix GestureDetector corners

* code refactor / organize

* Wip-gesture race: time to test on real device

* Fix multi finger gesture race

* Reset gesture winner correctly

* Use MultiFingerGesture during gesture race

* update MultiFingerGesture doc

* add debugMultiFingerGestureWinner / enableMultiFingerGestureRace

* Do not override original start point

* mapEventStream do not rely on MapController.ready

* emit MapEventFlingAnimationStart correctly

* remove expensive _positionedTapDetectorKey

* rebuild layers just once when Move and Rotate happens at the same time

* use different eventKey in example

* GestureDetector isn't rotated anymore

* Correct fling animation when map is rotated

* Make rotation operation cheaper

* add rotate flag for layers

* Revert "add rotate flag for layers"

This reverts commit 9e550fe.

* create rotate and non rotate layers

* Use Stream<Null> rebuild instead of dynamic

* #736 fix - rebuild layers when size changed with new pixelOrigin

* #736 fix2 - do not call onMoveSink after init

* #736 fix2 - handle rebuild layers without _updateSizeByOriginalSizeAndRotation method

* fix emit MapEventMove while multifinger

* try to fix dartanalyzer for Travis

* try to fix dartanalyzer for Travis 2

* Update tile_layer.dart

Co-authored-by: John Ryan <ryjohn@google.com>
  • Loading branch information
maRci002 and johnpryan committed Jan 29, 2021
1 parent ee6b83a commit d6b365e
Show file tree
Hide file tree
Showing 29 changed files with 1,561 additions and 325 deletions.
4 changes: 4 additions & 0 deletions example/android/app/src/main/AndroidManifest.xml
Expand Up @@ -5,6 +5,10 @@
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<application
android:name="io.flutter.app.FlutterApplication"
android:label="example"
Expand Down
2 changes: 2 additions & 0 deletions example/lib/main.dart
Expand Up @@ -21,6 +21,7 @@ import './pages/tap_to_add.dart';
import './pages/tile_loading_error_handle.dart';
import './pages/widgets.dart';
import './pages/wms_tile_layer.dart';
import 'pages/interactive_test_page.dart';

void main() => runApp(MyApp());

Expand Down Expand Up @@ -56,6 +57,7 @@ class MyApp extends StatelessWidget {
CustomCrsPage.route: (context) => CustomCrsPage(),
LiveLocationPage.route: (context) => LiveLocationPage(),
TileLoadingErrorHandle.route: (context) => TileLoadingErrorHandle(),
InteractiveTestPage.route: (context) => InteractiveTestPage(),
},
);
}
Expand Down
191 changes: 191 additions & 0 deletions example/lib/pages/interactive_test_page.dart
@@ -0,0 +1,191 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';

import '../widgets/drawer.dart';

class InteractiveTestPage extends StatefulWidget {
static const String route = 'interactive_test_page';

@override
State createState() {
return _InteractiveTestPageState();
}
}

class _InteractiveTestPageState extends State<InteractiveTestPage> {
MapController mapController;

// Enable pinchZoom and doubleTapZoomBy by default
int flags = InteractiveFlag.pinchZoom | InteractiveFlag.doubleTapZoom;

StreamSubscription<MapEvent> subscription;

@override
void initState() {
super.initState();
mapController = MapController();

subscription = mapController.mapEventStream.listen(onMapEvent);
}

@override
void dispose() {
subscription.cancel();

super.dispose();
}

void onMapEvent(MapEvent mapEvent) {
if (mapEvent is! MapEventMove && mapEvent is! MapEventRotate) {
// do not flood console with move and rotate events
print(mapEvent);
}
}

void updateFlags(int flag) {
if (InteractiveFlag.hasFlag(flags, flag)) {
// remove flag from flags
flags &= ~flag;
} else {
// add flag to flags
flags |= flag;
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test out Interactive flags!')),
drawer: buildDrawer(context, InteractiveTestPage.route),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
MaterialButton(
child: Text('Drag'),
color: InteractiveFlag.hasFlag(flags, InteractiveFlag.drag)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.drag);
});
},
),
MaterialButton(
child: Text('Fling'),
color: InteractiveFlag.hasFlag(
flags, InteractiveFlag.flingAnimation)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.flingAnimation);
});
},
),
MaterialButton(
child: Text('Pinch move'),
color:
InteractiveFlag.hasFlag(flags, InteractiveFlag.pinchMove)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.pinchMove);
});
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
MaterialButton(
child: Text('Double tap zoom'),
color: InteractiveFlag.hasFlag(
flags, InteractiveFlag.doubleTapZoom)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.doubleTapZoom);
});
},
),
MaterialButton(
child: Text('Rotate'),
color: InteractiveFlag.hasFlag(flags, InteractiveFlag.rotate)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.rotate);
});
},
),
MaterialButton(
child: Text('Pinch zoom'),
color:
InteractiveFlag.hasFlag(flags, InteractiveFlag.pinchZoom)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.pinchZoom);
});
},
),
],
),
Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Center(
child: StreamBuilder<MapEvent>(
stream: mapController.mapEventStream,
builder:
(BuildContext context, AsyncSnapshot<MapEvent> snapshot) {
if (!snapshot.hasData) {
return Text(
'Current event: none\nSource: none',
textAlign: TextAlign.center,
);
}

return Text(
'Current event: ${snapshot.data.runtimeType}\nSource: ${snapshot.data.source}',
textAlign: TextAlign.center,
);
},
),
),
),
Flexible(
child: FlutterMap(
mapController: mapController,
options: MapOptions(
center: LatLng(51.5, -0.09),
zoom: 11.0,
interactiveFlags: flags,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
),
],
),
),
],
),
),
);
}
}
37 changes: 31 additions & 6 deletions example/lib/pages/live_location.dart
Expand Up @@ -4,6 +4,8 @@ import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
import 'package:location/location.dart';

import '../widgets/drawer.dart';

class LiveLocationPage extends StatefulWidget {
static const String route = '/live_location';

Expand All @@ -15,11 +17,13 @@ class _LiveLocationPageState extends State<LiveLocationPage> {
LocationData _currentLocation;
MapController _mapController;

bool _liveUpdate = true;
bool _liveUpdate = false;
bool _permission = false;

String _serviceError = '';

var interActiveFlags = InteractiveFlag.all;

final Location _locationService = Location();

@override
Expand Down Expand Up @@ -114,7 +118,7 @@ class _LiveLocationPageState extends State<LiveLocationPage> {

return Scaffold(
appBar: AppBar(title: Text('Home')),
//drawer: buildDrawer(context, route),
drawer: buildDrawer(context, LiveLocationPage.route),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
Expand All @@ -135,6 +139,7 @@ class _LiveLocationPageState extends State<LiveLocationPage> {
center:
LatLng(currentLatLng.latitude, currentLatLng.longitude),
zoom: 5.0,
interactiveFlags: interActiveFlags,
),
layers: [
TileLayerOptions(
Expand All @@ -153,10 +158,30 @@ class _LiveLocationPageState extends State<LiveLocationPage> {
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _liveUpdate = !_liveUpdate,
child: _liveUpdate ? Icon(Icons.location_on) : Icon(Icons.location_off),
),
floatingActionButton: Builder(builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
setState(() {
_liveUpdate = !_liveUpdate;

if (_liveUpdate) {
interActiveFlags = InteractiveFlag.rotate |
InteractiveFlag.pinchZoom |
InteractiveFlag.doubleTapZoom;

Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
'In live update mode only zoom and rotation are enable'),
));
} else {
interActiveFlags = InteractiveFlag.all;
}
});
},
child:
_liveUpdate ? Icon(Icons.location_on) : Icon(Icons.location_off),
);
}),
);
}
}

0 comments on commit d6b365e

Please sign in to comment.