Skip to content

Instantly share code, notes, and snippets.

@nateshmbhat
Created October 3, 2020 11:45
Show Gist options
  • Save nateshmbhat/01ec6b173950b73e883239fe6f4378c5 to your computer and use it in GitHub Desktop.
Save nateshmbhat/01ec6b173950b73e883239fe6f4378c5 to your computer and use it in GitHub Desktop.
Shaking Error Text Widget
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:simple_animations/simple_animations.dart';
enum ErrorAnimationProp { offset }
class ShakingErrorText extends StatelessWidget {
final ShakingErrorController controller;
final int timesToShake;
final MultiTween<ErrorAnimationProp> _tween;
ShakingErrorText({
this.controller,
this.timesToShake = 4,
}) : _tween = MultiTween<ErrorAnimationProp>() {
List.generate(
timesToShake,
(_) => _tween
..add(ErrorAnimationProp.offset, Tween<double>(begin: 0, end: 10), Duration(milliseconds: 100))
..add(ErrorAnimationProp.offset, Tween<double>(begin: 10, end: -10), Duration(milliseconds: 100))
..add(ErrorAnimationProp.offset, Tween<double>(begin: -10, end: 0), Duration(milliseconds: 100)));
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ShakingErrorController>.value(
value: controller,
child: Consumer<ShakingErrorController>(
builder: (context, errorController, child) {
return CustomAnimation<MultiTweenValues<ErrorAnimationProp>>(
control: errorController.controlSignal,
curve: Curves.easeOut,
duration: _tween.duration,
tween: _tween,
animationStatusListener: (status) {
if (status == AnimationStatus.forward) {
controller._onAnimationStarted();
}
},
builder: (BuildContext context, Widget child, tweenValues) {
return Transform.translate(
offset: Offset(tweenValues.get(ErrorAnimationProp.offset), 0),
child: child,
);
},
child: Visibility(
visible: controller.isVisible && controller.isMounted,
maintainSize: controller.isMounted,
maintainAnimation: controller.isMounted,
maintainState: controller.isMounted,
child: Text(
errorController.errorText,
textAlign: TextAlign.start,
style: TextStyle(color: Colors.red)
),
),
);
},
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:simple_animations/simple_animations.dart';
class ShakingErrorController extends ChangeNotifier {
String _errorText;
bool _isVisible = true;
bool _isMounted = true;
CustomAnimationControl _controlSignal = CustomAnimationControl.PLAY;
ShakingErrorController(
{String initialErrorText = 'Error', bool revealWithAnimation = true, bool hiddenInitially = true})
: _errorText = initialErrorText ?? '',
_isVisible = !hiddenInitially,
_controlSignal = (revealWithAnimation ?? true) ? CustomAnimationControl.PLAY : CustomAnimationControl.STOP;
set errorText(String errorText) {
_errorText = errorText;
notifyListeners();
}
void _onAnimationStarted() {
_controlSignal = CustomAnimationControl.PLAY;
}
void shakeErrorText() {
_controlSignal = CustomAnimationControl.PLAY_FROM_START;
notifyListeners();
}
///fully [unmount] and remove the error text
void unMountError() {
_isMounted = false;
notifyListeners();
}
///[remount] error text. will not be effective if its already mounted
void mountError() {
_isMounted = true;
notifyListeners();
}
///hide the error. but it will still be taking its space.
void hideError() {
_isVisible = false;
notifyListeners();
}
///just shows error without any animation
void showError() {
_isVisible = true;
notifyListeners();
}
bool get isMounted => _isMounted;
///shows error with the reveal [animation]
void revealError() {
showError();
shakeErrorText();
}
bool get isVisible => _isVisible;
String get errorText => _errorText;
CustomAnimationControl get controlSignal => _controlSignal;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment