DimZ
DimZ

Reputation: 427

Make a widget in front of an overlay

I'm trying to reproduce the same contextual menu of Pinterest, in Flutter. So I have an overlay, which displays my contextual menu with a background, and I'd like to keep also the current element in front of the overlay.

Here are 2 videos: the Pinterest menu vs My Flutter menu.

To make an overlay I'm using flutter_portal package.

Here is the code of the blue card widget, with the overlay stuff:

import 'package:flutter/material.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:vector_math/vector_math.dart' show radians;

class CardWidget extends StatefulWidget {
  @override
  _CardWidgetState createState() => _CardWidgetState();
}

class _CardWidgetState extends State<CardWidget> with SingleTickerProviderStateMixin {
  late AnimationController controller;
  late Animation<double> degreeAnimation;
  late Animation<double> opacityAnimation;
  bool isMenuOpen = false;
  double menuPosX = 0;
  double menuPosY = 0;

  @override
  void initState() {
    controller = AnimationController(vsync: this, duration: Duration(milliseconds: 200))
      ..addListener(() {
        setState(() {});
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.forward) {
          isMenuOpen = true;
        } else if (status == AnimationStatus.dismissed) {
          isMenuOpen = false;
        }
      });
    degreeAnimation =
        Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: controller, curve: Curves.easeOutBack));
    opacityAnimation =
        Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: controller, curve: Curves.easeOutExpo));

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 63.5 / 88.9,
      child: PortalEntry(
        visible: isMenuOpen,
        portal: Container(
          color: Colors.black.withOpacity(opacityAnimation.value / 2),
          child: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () {
              controller.reverse();
            },
          ),
        ),
        child: PortalEntry(
          visible: isMenuOpen,
          child: GestureDetector(
            onTapDown: (details) {

              if (controller.isCompleted) {
                controller.reverse();
              } else {
                menuPosX = details.globalPosition.dx;
                menuPosY = details.globalPosition.dy;

                controller.forward();
              }
            },
            // Blue card content
            child: Container(
              decoration: BoxDecoration(
                color: Colors.blue,
                borderRadius: BorderRadius.all(
                  Radius.circular(8),
                ),
              ),
              child: Center(
                child: Text(
                  'Card Widget',
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ),
          ),
          // Current contextual Menu
          portal: ContextualMenuWidget(),
        ),
      ),
    );
  }
}

Thank you for your help!

Upvotes: 0

Views: 481

Answers (2)

DimZ
DimZ

Reputation: 427

Thanks to orotype, instead of making a black overlay, I finally wrapped my cards with an AnimatedOpacity, and passed a callback when the contextual menu is opened/closed to trig the animation.

Result here!

I don't know if this is the best solution, but I like the result.

Upvotes: 0

orotype
orotype

Reputation: 459

Maybe instead of an trying to add an overlay, you can change the color of all the other cards to the same as the background. By that you would achieve the same effect.

You can check if isMenuOpen is true and save the index of the card on which it was clicked, and in your grid builder function you can change the color of all the cards to the same as the background.

Upvotes: 1

Related Questions