Skip to content

Instantly share code, notes, and snippets.

@tarek360
Created December 10, 2019 09:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tarek360/9008eca7f817e6bf9b53a5304c3c772f to your computer and use it in GitHub Desktop.
Save tarek360/9008eca7f817e6bf9b53a5304c3c772f to your computer and use it in GitHub Desktop.
A TopAlert to show at the top of any page (widget).
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Top Alert View',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Top Alert View'),
),
body: TopAlert(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Push the button to show an Alert!',
),
MyButton()
],
),
),
),
);
}
}
class MyButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return IconButton(
color: Colors.red,
iconSize: 56,
icon: Icon(Icons.info),
onPressed: () {
TopAlert.of(context).showAlert(
Container(
color: Colors.red,
child: Center(
child: Text(
'Something went wrong!',
style: Theme.of(context)
.textTheme
.subhead
.copyWith(color: Colors.white),
),
),
),
);
},
);
}
}
// Alert Widget
class TopAlert extends StatefulWidget {
final Widget child;
final Duration animationDuration;
final Duration displayDuration;
TopAlert({
@required this.child,
this.animationDuration: const Duration(milliseconds: 200),
this.displayDuration: const Duration(seconds: 2),
});
@override
TopAlertState createState() => TopAlertState();
static TopAlertState of(BuildContext context, {bool nullOk = false}) {
assert(nullOk != null);
assert(context != null);
final TopAlertState result =
context.findAncestorStateOfType<TopAlertState>();
if (nullOk || result != null) return result;
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary(
'TopAlert.of() called with a context that does not contain a TopAlert.'),
ErrorDescription(
'No TopAlert ancestor could be found starting from the context that was passed to TopAlert.of(). '
'This usually happens when the context provided is from the same StatefulWidget as that '
'whose build function actually creates the TopAlert widget being sought.'),
ErrorHint(
'There are several ways to avoid this problem. The simplest is to use a Builder to get a '
'context that is "under" the TopAlert. For an example of this, please see:'),
ErrorHint(
'A more efficient solution is to split your build function into several widgets. This '
'introduces a new context from which you can obtain the TopAlert. In this solution, '
'you would have an outer widget that creates the TopAlert populated by instances of '
'your new inner widgets, and then in these inner widgets you would use TopAlert.of().\n'
'A less elegant but more expedient solution is assign a GlobalKey to the TopAlert, '
'then use the key.currentState property to obtain the TopAlert rather than '
'using the TopAlert.of() function.'),
context.describeElement('The context used was')
]);
}
}
class TopAlertState extends State<TopAlert> {
bool _displayed = false;
Widget _alertView;
Duration _animationDuration;
Duration _displayDuration;
@override
void initState() {
super.initState();
_animationDuration = widget.animationDuration;
_displayDuration = widget.displayDuration;
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
widget.child,
AnimatedContainer(
height: _displayed ? 56 : 0,
width: double.infinity,
duration: _animationDuration,
curve: Curves.easeOutCubic,
child: _alertView ?? Container(),
onEnd: _delayAndHide,
),
],
);
}
void showAlert(
Widget alertView, {
Duration animationDuration,
Duration displayDuration,
}) {
assert(alertView != null);
_animationDuration = animationDuration ?? widget.animationDuration;
_displayDuration = displayDuration ?? widget.displayDuration;
if (!_displayed) {
_alertView = alertView;
setState(() {
_displayed = true;
});
}
}
void _delayAndHide() {
if (!_displayed) {
return;
}
Future.delayed(_displayDuration, () {
setState(() {
_displayed = false;
});
// Clear _alertView
Future.delayed(_animationDuration, () {
_alertView = null;
});
});
}
}
@tarek360
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment