Question: I'm trying to figure out how to notify user with alert that comes from top of the screen like normal push notification does. 
How can I alert user from top of the screen.  

`AlertDialog` is not customizable so I'm stuck with this. Is there any way to show something like alert or snack bar from top of the screen?

Answer: 
Flutter gives you the possiblity to create notifications with the help of the class [Overlay](https://docs.flutter.io/flutter/widgets/Overlay-class.html). To animate these entering the screen from the top you can use the [SlideTransition](https://docs.flutter.io/flutter/widgets/SlideTransition-class.html) in combination with an [AnimationController](https://docs.flutter.io/flutter/animation/AnimationController/AnimationController.html). Here is an example application I created:

[![enter image description here](https://i.stack.imgur.com/MMMig.gif)](https://i.stack.imgur.com/MMMig.gif)

```
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Home());
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: RaisedButton.icon(
          icon: Icon(Icons.notifications_active),
          label: Text('Notify!'),
          onPressed: () {
            Navigator.of(context)
                .overlay
                .insert(OverlayEntry(builder: (BuildContext context) {
              return FunkyNotification();
            }));
          },
        ),
      ),
    );
  }
}

class FunkyNotification extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => FunkyNotificationState();
}

class FunkyNotificationState extends State<FunkyNotification>
    with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<Offset> position;

  @override
  void initState() {
    super.initState();

    controller =
        AnimationController(vsync: this, duration: Duration(milliseconds: 750));
    position = Tween<Offset>(begin: Offset(0.0, -4.0), end: Offset.zero)
        .animate(
            CurvedAnimation(parent: controller, curve: Curves.bounceInOut));

    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Material(
        color: Colors.transparent,
        child: Align(
          alignment: Alignment.topCenter,
          child: Padding(
            padding: EdgeInsets.only(top: 32.0),
            child: SlideTransition(
              position: position,
              child: Container(
                decoration: ShapeDecoration(
                    color: Colors.deepPurple,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(16.0))),
                child: Padding(
                  padding: EdgeInsets.all(10.0),
                  child: Text(
                    'Notification!',
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.bold),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

```
Here **you can dismiss notifications using the swipe up or down**. This is the perfect notification for promotion in-app.

```
class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> with TickerProviderStateMixin {
  bool _fromTop = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.fireplace_outlined),
        onPressed: () {
          showGeneralDialog(
            barrierLabel: "Label",
            barrierDismissible: true,
            barrierColor: Colors.transparent,
            transitionDuration: Duration(milliseconds: 700),
            context: context,
            pageBuilder: (context, anim1, anim2) {
              return GestureDetector(
                onVerticalDragUpdate: (dragUpdateDetails) {
                  Navigator.of(context).pop();
                },
                child: Column(
                  children: [
                    SizedBox(height: 40),
                    Card(
                      margin:
                          EdgeInsets.symmetric(vertical: 20, horizontal: 10),
                      child: Container(
                        height: 100,
                        child: Image.asset('lib/model/promo.png',
                            fit: BoxFit.fill),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(40),
                        ),
                      ),
                    ),
                  ],
                ),
              );
            },
            transitionBuilder: (context, anim1, anim2, child) {
              return SlideTransition(
                position: anim1.drive(Tween(
                        begin: Offset(0, _fromTop ? -1 : 1), end: Offset(0, 0))
                    .chain(CurveTween(curve: Sprung()))),
                child: child,
              );
            },
          );
        },
      ),
    );
  }
}

class Sprung extends Curve {
  factory Sprung([double damping = 20]) => Sprung.custom(damping: damping);

  Sprung.custom({
    double damping = 20,
    double stiffness = 180,
    double mass = 1.0,
    double velocity = 0.0,
  }) : this._sim = SpringSimulation(
          SpringDescription(
            damping: damping,
            mass: mass,
            stiffness: stiffness,
          ),
          0.0,
          1.0,
          velocity,
        );

  final SpringSimulation _sim;

  @override
  double transform(double t) => _sim.x(t) + t * (1 - _sim.x(1.0));
}

```