Flutter device shake iOS plugin

3,308

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();
  }
Share:
3,308
Mark Mooibroek
Author by

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, 2022

Comments

  • Mark Mooibroek
    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
    Mark Mooibroek almost 6 years
    Yeah, maybe thats even a better approach :-) Thanks for pointing that out!