Home > OS >  MouseRegion doesn't cover positioned element in stack
MouseRegion doesn't cover positioned element in stack

Time:08-03

I struggle to get a positioned object that I have in a stack to keep the mouse region that I have defined on an element that is bigger than the initial stacksize. The content gets shown, but it doesn't keep the mouse region. Meaning, even I'm still on top of the positioned object, it disappears when the mouse leaves the defined area. I also can't switch the size of the element because that would cause my content to get shifted.

enter image description here

Do you have any suggestions on how to solve that? In HTML, this behaviour is standard. So it puzzles me that Flutter struggles so much with it.

Here a code example

MouseRegion(
        onEnter: (_) {
          isButtonHovered = true;
          setState(() {});
        },
        onExit: (_) async {
          isButtonHovered = false;
          setState(() {});
        },
        child: SizedBox(
          width: 200,
          height: 100,
            child: Stack(
          clipBehavior: Clip.none,
          alignment: Alignment.bottomLeft,
          children: [
            Container(
              color: Colors.blue,
              width: 200,
              height: 100,
            ),
            isButtonHovered
                ? Positioned(
                    bottom: 0,
                    left: 0,
                    child: Container(
                      color: Colors.red,
                      width: 200,
                      height: 500,
                    ))
                : Container(),
          ],
        )));

CodePudding user response:

The mouse region is constrained within the 200 of the sized box.. You can also change the height of the sized box based on the mouse hover like this

import 'package:flutter/material.dart';



void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  bool isButtonHovered = false;
  @override
  Widget build(BuildContext context) {
    return MouseRegion(
        onEnter: (_) {
          isButtonHovered = true;
          setState(() {});
        },
        onExit: (_) async {
          isButtonHovered = false;
          setState(() {});
        },
        child: SizedBox(
          width: 200,
          height: isButtonHovered?500:100,//<---Here
            child: Stack(
          clipBehavior: Clip.none,
          alignment: Alignment.bottomLeft,
          children: [
            Container(
              color: Colors.blue,
              width: 200,
              height: 100,
            ),
            isButtonHovered
                ? Positioned(
                    bottom: 0,
                    left: 0,
                    child: Container(
                      color: Colors.red,
                      width: 200,
                      height: 500,
                    ))
                : Container(),
            
          ],
        )));
  }
}

Edit

I think the layout you created is wrong. I created a working demo for you. Please check this

import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  bool isButtonHovered = false;
  @override
  Widget build(BuildContext context) {
    return Stack(children: [
      Column(children: [
        Text("Content"),
        MouseRegion(
            onEnter: (_) {
              isButtonHovered = true;
              setState(() {});
            },
            child: Container(height: 200, width: 200, color: Colors.blue)),
        Text("Content"),
      ]),
      if (isButtonHovered)
        MouseRegion(
          onExit: (_) {
              isButtonHovered = false;
              setState(() {});
            },
          child: Container(height: 500, width: 200, color: Colors.red.withOpacity(0.5)))
    ]);
  }
}

The mouse region will not work outside a SizedBox with specific size even if we set the clip to none in a stack that's inside the sized box..

CodePudding user response:

I think the structure will get initially 500 height. And rather than using onEnter it is better to use onHover. Also, I think enabling the max container will be based on hover position.

Text('Content'),
SizedBox(
  width: 200,
  height: 500,
  child: MouseRegion(
    onEnter: (details) {},
    onHover: (event) {
      final dx = event.localPosition.dy;
      // enter position > max height - min blue Box
      if (dx > 500 - 100) {
        isButtonHovered = true;
        setState(() {});
      }
    },
    onExit: (details) async {
      isButtonHovered = false;
      setState(() {});
    },
    child: Stack(
      clipBehavior: Clip.none,
      alignment: Alignment.bottomLeft,
      children: [
        Positioned(
          bottom: 0,
          left: 0,
          child: Container(
            color: Colors.blue,
            width: 200,
            height: 100,
          ),
        ),
        isButtonHovered
            ? Positioned(
                bottom: 0,
                left: 0,
                child: Container(
                  color: Colors.red.withOpacity(0.8),
                  width: 200,
                  height: 500,
                ))
            : Container(),
      ],
    ),
  ),
),
Text('Content'),
  • Related