Open Source

Flutter package

haptic_kit

Haptic feedback, vibration and animated widgets for Flutter — the right haptic at the right moment.

v2.1.223.3k / month32 likesMITAndroid · iOS9 animated widgets

Patterns & haptics API

The HapticPattern builder, predefined OS effects, ready-made vibration patterns, waveforms and typed errors.

source: README.md

Core Haptics

HapticPattern builder

HapticPattern is a fluent builder for Core Haptics patterns. Chain transient taps, pauses and continuous events, each with a per-event intensity and sharpness in the range 0.0–1.0, then call play().

Building a patterndart
await HapticPattern.builder()
    .tap(intensity: 0.4, sharpness: 0.6)
    .pause(const Duration(milliseconds: 80))
    .tap(intensity: 1.0, sharpness: 0.9)
    .continuous(
      duration: const Duration(milliseconds: 250),
      intensity: 0.7,
      sharpness: 0.3,
    )
    .play();
Builder APIdart
factory HapticPattern.builder() = HapticPattern._;

HapticPattern tap({
  required double intensity,
  required double sharpness,
})

HapticPattern continuous({
  required Duration duration,
  required double intensity,
  required double sharpness,
})

HapticPattern pause(Duration duration)

HapticPattern addEvent(HapticEvent event)

int get length          // Number of events queued so far.
List<HapticEvent> get events  // Snapshot of the current event list.

Future<void> play()

HapticEvent

dart
const HapticEvent({
  required this.intensity,
  required this.sharpness,
  this.duration = Duration.zero,
  this.relativeTime = Duration.zero,
})
FieldRange / typeMeaning
intensitydouble 0.0–1.0Overall strength of the event.
sharpnessdouble 0.0–1.0Perceptual 'sharpness' of the event (iOS only; ignored on Android, which has no equivalent).
durationDuration, default zeroIf non-zero, the event is continuous; otherwise it is treated as a single tap.
relativeTimeDuration, default zeroOffset from pattern start at which this event begins.

Platform translation & graceful degradation

On iOS (iPhone 8+) a pattern renders as a CHHapticPattern with hapticTransient / hapticContinuous events. On Android (API 26+) intensity is mapped to amplitude and sharpness is ignored (no perceptual analogue). On older devices, play() throws UnsupportedHapticException — guard with HapticCapabilities.query() if you need to fall back. An empty builder throws InvalidVibrationArgumentException, as do continuous / pause durations of 0 ms or less.

OS effects

Predefined effects

PredefinedEffect maps to VibrationEffect.EFFECT_* constants on Android API 29+, and to the closest HapticFeedback style on iOS and older Android.

PredefinedEffectdart
enum PredefinedEffect {
  tick,        // Android: EFFECT_TICK
  click,       // Android: EFFECT_CLICK
  doubleClick, // Android: EFFECT_DOUBLE_CLICK
  heavyClick,  // Android: EFFECT_HEAVY_CLICK
}
Usagedart
await Vibration.playPredefined(PredefinedEffect.doubleClick);

Presets

VibrationPatterns

Ready-made patterns you can drop straight into a UI callback. Each entry returns a Future so playback can be awaited.

PresetSignatureWhat it doesBuilt on
heartbeatstatic Future<void> heartbeat()Two short pulses mimicking a heartbeat.waveform, amplitudes [0, 200, 0, 200, 0]
notificationstatic Future<void> notification()Three escalating pulses — typical incoming-notification pattern.waveform, amplitudes [0, 120, 0, 180, 0, 255]
alarmstatic Future<void> alarm({bool repeat = true})Long ringing pattern — alarms / incoming calls. Loops by default.waveform, repeat: repeat ? 0 : -1
tickstatic Future<void> tick()Single very short tick — scrub / scroll feedback a hair stronger than selection.vibrate(duration: 10 ms, amplitude: 80)
doubleTapstatic Future<void> doubleTap()Two quick, equal taps — e.g. a double-tap acknowledgement.HapticPattern: 2× tap(0.8 / 0.7), 90 ms pause
successstatic Future<void> success()Confirmation: light tap → strong tap.HapticPattern: tap(0.5 / 0.5) → 80 ms → tap(1.0 / 0.8)
failurestatic Future<void> failure()Failure / cancel: two strong taps.HapticPattern: 2× tap(1.0 / 0.9), 120 ms pause
chargeUpstatic Future<void> chargeUp({Duration duration = const Duration(milliseconds: 600)})Long ramp from soft to strong — 'charging up' UI moments.HapticPattern continuous, intensity: 1.0, sharpness: 0.2

Vibration

Custom waveforms

For raw control over duration and amplitude, drive the vibrator directly. timings is a list of off/on durations starting with an off period (Android createWaveform convention); amplitudes, if provided, must have the same length and use values in [0, 255] (0 = a pause). Set repeat to the index in timings to loop from, or -1 for no loop.

Vibration APIdart
const int kMaxAmplitude = 255;
const int kMinAmplitude = 1;

static Future<void> vibrate({
  required Duration duration,
  int? amplitude,
})

static Future<void> vibrateWaveform({
  required List<Duration> timings,
  List<int>? amplitudes,
  int repeat = -1,
})

static Future<void> playPredefined(PredefinedEffect effect)

static Future<void> cancel()
Custom waveformdart
// Three pulses with growing amplitude
await Vibration.vibrateWaveform(
  timings: const [
    Duration.zero,
    Duration(milliseconds: 100),
    Duration(milliseconds: 100),
    Duration(milliseconds: 100),
    Duration(milliseconds: 100),
    Duration(milliseconds: 100),
  ],
  amplitudes: const [0, 80, 0, 160, 0, 255],
);

vibrate throws InvalidVibrationArgumentException when the duration is zero/negative or the amplitude is outside [1, 255]; pass null for the device default, and values are silently clamped on devices without amplitude control. On iOS without Core Haptics, a waveform falls back to a sequence of system vibrations approximating timings.

Detection

HapticCapabilities

Query the device once with HapticCapabilities.query() and cache the result — the values do not change at runtime. Use it to pick the richest effect the hardware can actually render.

dart
static Future<HapticCapabilities> query()
FieldTypeMeaning
hasVibratorboolDevice has any kind of vibrator hardware.
hasAmplitudeControlboolDevice can render variable-amplitude waveforms. Android: Vibrator.hasAmplitudeControl() (API 26+); iOS: true when Core Haptics is available.
supportsCustomPatternsboolCustom HapticPatterns with intensity + sharpness. Android: API 26+ with amplitude control; iOS: Core Haptics devices (iPhone 8+).
supportsPredefinedEffectsboolVibrationEffect.createPredefined (Android API 29+). Always false on iOS — predefined calls are translated to the closest UIImpactFeedbackGenerator style instead.
supportsImpactFeedbackboolUIImpactFeedbackGenerator-style taps. iOS: true on iOS 10+; Android: true on API 23+ via the lightweight HapticFeedbackConstants path, even without an amplitude-controlled vibrator.
Graceful degradationdart
final caps = await HapticCapabilities.query();
if (caps.supportsCustomPatterns) {
  await VibrationPatterns.success();
} else {
  await Haptics.notification(HapticNotificationStyle.success);
}

Errors

Typed error handling

All public APIs throw subclasses of VibrationException. The base class is sealed, so an exhaustive switch over the three concrete types is possible.

exceptions.dartdart
sealed class VibrationException implements Exception {
  const VibrationException(this.message);
  final String message;
}

class UnsupportedHapticException extends VibrationException {
  const UnsupportedHapticException(super.message);
}

class InvalidVibrationArgumentException extends VibrationException {
  const InvalidVibrationArgumentException(super.message);
}

class PlatformVibrationException extends VibrationException {
  const PlatformVibrationException(super.message, {this.code});
  final String? code;
}
ExceptionThrown when
InvalidVibrationArgumentExceptionA parameter is out of range (negative duration, amplitude > 255, mismatched lists, …).
UnsupportedHapticExceptionThe device cannot render the requested capability.
PlatformVibrationExceptionThe native side returned an error or the plugin is not registered.

Let's make something together.

If you have any questions about a new project or other inquiries, feel free to contact us. We will get back to you as soon as possible.

Codigee
We are using cookies. Learn more