Add vibrations in a Xamarin.iOS app

Long time ago I've worked on adding Haptic Feedback, aka. vibrations on a Xamarin.Native app. Here is how it works for iOS :

I've isolated these 7 different types of Haptic Feedback available in the iOS SDK :

    public enum HapticFeedbackType
    {
        ImpactHeavy, // Heavy impact
        ImpactMedium, // Medium impact
        ImpactLight, // Light impact
        Selection, // To tick while scrolling through a scrollview or carousel
        NotificationError, // When an in-app error notification occurs
        NotificationWarning, // When an in-app warning notification occurs
        NotificationSuccess // When an in-app success notification occurs
    }

In iOS SDK, to use a Feedback Generator you need to :

  1. Instantiate the Generator
  2. Prepare the Generator (optional)
  3. Trigger Feedback
  4. Release the Generator (optional).

Instantiate the Generator

private UIImpactFeedbackGenerator _impactHeavyFeedbackGenerator;
private UIImpactFeedbackGenerator _impactMediumFeedbackGenerator;
private UIImpactFeedbackGenerator _impactLightFeedbackGenerator;
private UISelectionFeedbackGenerator _selectionFeedbackGenerator;
private UINotificationFeedbackGenerator _notificationFeedbackGenerator;

public HapticFeedbackHelperIOS()
{
    _impactHeavyFeedbackGenerator = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Heavy);
    _impactMediumFeedbackGenerator = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Medium);
    _impactLightFeedbackGenerator = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Light);
    _selectionFeedbackGenerator = new UISelectionFeedbackGenerator();
    _notificationFeedbackGenerator = new UINotificationFeedbackGenerator();
}

Prepare the Generator (optional)

This step is optional. This step exists because the phone may need half a second to prepare the Haptic effect before triggering it. Without this step it might delay (a little) the triggering of a vibration.

public void PrepareHapticFeedback(HapticFeedbackType type)
{
    switch (type)
    {
        case HapticFeedbackType.ImpactHeavy:
            _impactHeavyFeedbackGenerator.Prepare();
            break;
        case HapticFeedbackType.ImpactMedium:
            _impactMediumFeedbackGenerator.Prepare();
            break;
        case HapticFeedbackType.ImpactLight:
            _impactLightFeedbackGenerator.Prepare();
            break;
        case HapticFeedbackType.Selection:
            _selectionFeedbackGenerator.Prepare();
            break;
        case HapticFeedbackType.NotificationError:
        case HapticFeedbackType.NotificationWarning:
        case HapticFeedbackType.NotificationSuccess:
            _notificationFeedbackGenerator.Prepare();
            break;
    }
}

Trigger the feedback

public static void ExecuteHapticFeedback(HapticFeedbackType type)
{
    switch (type)
    {
        case HapticFeedbackType.ImpactHeavy:
            _impactHeavyFeedbackGenerator.ImpactOccurred();
            break;
        case HapticFeedbackType.ImpactMedium:
            _impactMediumFeedbackGenerator.ImpactOccurred();
            break;
        case HapticFeedbackType.ImpactLight:
            _impactLightFeedbackGenerator.ImpactOccurred();
            break;
        case HapticFeedbackType.Selection:
            _selectionFeedbackGenerator.SelectionChanged();
            break;
        case HapticFeedbackType.NotificationError:
            _notificationFeedbackGenerator.NotificationOccurred(UINotificationFeedbackType.Error);
            break;
        case HapticFeedbackType.NotificationWarning:
            _notificationFeedbackGenerator.NotificationOccurred(UINotificationFeedbackType.Warning);
            break;
        case HapticFeedbackType.NotificationSuccess:
            _notificationFeedbackGenerator.NotificationOccurred(UINotificationFeedbackType.Success);
            break;
    }
}

Release the Generator (optional)

This is also optional. It will free the memory of the unused Generators.

public void Dispose()
{
    _impactHeavyFeedbackGenerator = null;
    _impactMediumFeedbackGenerator = null;
    _impactLightFeedbackGenerator = null;
    _selectionFeedbackGenerator = null;
    _notificationFeedbackGenerator = null;
}

All this packed in a nice Gist

Find the Gist here : https://gist.github.com/framinosona/489ea6e0bc04689b5d251eda30f6c220

To use HapticFeedbackHelperIOS

ImpactHeavyButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.ImpactHeavy);
ImpactHeavyButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.ImpactHeavy);

ImpactMediumButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.ImpactMedium);
ImpactMediumButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.ImpactMedium);

ImpactLightButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.ImpactLight);
ImpactLightButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.ImpactLight);

SelectionButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.Selection);
SelectionButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.Selection);

NotificationErrorButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.NotificationError);
NotificationErrorButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.NotificationError);

NotificationWarningButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.NotificationWarning);
NotificationWarningButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.NotificationWarning);

NotificationSuccessButton.TouchDown += (sender, e) => _hapticFeedbackHelperIOS.PrepareHapticFeedback(HapticFeedbackType.NotificationSuccess);
NotificationSuccessButton.TouchUpInside += (sender, e) => _hapticFeedbackHelperIOS.ExecuteHapticFeedback(HapticFeedbackType.NotificationSuccess);