Flutter device shake iOS plugin
Solution 1
The Flutter Team has already published a plugin called sensors
, which can be used to detect motion from the accelerometer (and gyroscope).
import 'package:sensors/sensors.dart';
accelerometerEvents.listen((AccelerometerEvent event) {
// "calculate" "shakes" here
});
The event
contains x
, y
and z
values. Combining this with time will make it possible to check for shakes.
I am just pointing this out because it is way less to go than creating a full plugin from scratch.
Solution 2
You could try this plugin: shake_event
It's pretty simple to work with and works both for iOS and Android.
Solution 3
I ran into the same issue, so I figured Reactive Programming
and RxDart
could help.
You can create a BLoC
(Business logic component) called sensor_bloc.dart
:
import 'dart:async';
import 'dart:math';
import 'package:rxdart/rxdart.dart';
import 'package:sensors/sensors.dart';
class SensorBloc {
StreamSubscription<dynamic> _accelerometerStream;
//INPUT
final _thresholdController = StreamController<int>();
Sink<int> get threshold => _thresholdController.sink;
// OUTPUT
final _shakeDetector = StreamController<bool>();
Stream<bool> get shakeEvent => _shakeDetector.stream.transform(ThrottleStreamTransformer(Duration(seconds: 2)));
SensorBloc() {
const CircularBufferSize = 10;
double detectionThreshold = 70.0;
List<double> circularBuffer = List.filled(CircularBufferSize,0.0);
int index = 0;
double minX=0.0, maxX=0.0;
_thresholdController.stream.listen((value){
// safety
if (value > 30) detectionThreshold = value*1.0;
});
_accelerometerStream = accelerometerEvents.listen((AccelerometerEvent event){
index = (index == CircularBufferSize -1 ) ? 0: index+1;
var oldX = circularBuffer[index];
if (oldX == maxX) {
maxX = circularBuffer.reduce(max);
}
if (oldX == minX) {
minX = circularBuffer.reduce(min);
}
circularBuffer[index] = event.x;
if (event.x < minX ) minX=event.x;
if (event.x> maxX) maxX = event.x;
if (maxX-minX>detectionThreshold)
{
_shakeDetector.add(true);
circularBuffer.fillRange(0, CircularBufferSize, 0.0);
minX=0.0;
maxX=0.0;
}
});
}
void dispose() {
_shakeDetector.close();
_accelerometerStream.cancel();
_thresholdController.close();
}
}
Then, just subscribe to its events in your widget :
Declare StreamSubscription<bool> shakeSubscriber ;
in your state, and hook to lifecycle events
(NB: I use a InheritedWidget giving me access to the umbrella BLoC via the static function MainWidget.bloc(context)
):
StreamSubscription<bool> shakeSubscriber ;
@override
Widget build(BuildContext context) {
if(shakeSubscriber == null ) {
MainWidget.bloc(context).sensorBloc.shakeEvent.listen((_){
print("SHAKE ! *************************");
});
}
return _buildMainScaffold();
}
@override
void dispose() {
if(shakeSubscriber != null ) shakeSubscriber.cancel();
super.dispose();
}
Mark Mooibroek
Just another developer :-) I live in the Netherlands I'm the father of 4 beautiful kids I'm passionate about programming
Updated on December 05, 2022Comments
-
Mark Mooibroek over 1 year
Evening guys,
Im looking into building a plugin for Flutter that detects if the device is shaking. Now i've found how to technically do it in Swift (Detect shake gesture IOS Swift) but im stuck on how to hook it up as a Flutter plugin, because i don't have direct access to the view controller lifecycle events.
Need a way to hook up
- viewDidLoad
- canBecomeFirstResponder
- motionEnded
Can anyone nudge me in the right direction?
-
Mark Mooibroek almost 6 yearsYeah, maybe thats even a better approach :-) Thanks for pointing that out!