getx icon indicating copy to clipboard operation
getx copied to clipboard

Bug Hiding all children when using Stack() with Visibility() or IF (visibility) for a child

Open thiago-delmotte-homelend opened this issue 1 year ago • 4 comments

Describe the bug Using a simple Stack() structure when it is necessary to hide a child widget results in hiding all the children. With other widgets this does not happen, for example Column. It works with StatefulWidget.

example:

VIEW

class HousePlanView extends GetView<HousePlanController> {
  const HousePlanView({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: controller.obx(
        (_) => Stack(
          children: [
            Positioned(
              top: 10,
              left: 10,
              child: Container(
                width: 100,
                height: 100,
                color: Colors.blue,
              ),
            ),
            Obx(() {
              if (controller.isKitchenSwitchedOn.value) {
                return Positioned(
                  top: 50,
                  left: 50,
                  child: Container(
                    width: 120,
                    height: 120,
                    color: Colors.green,
                  ),
                );
              }
              return const SizedBox.shrink();
            }),
            Positioned(
              top: 95,
              left: 75,
              child: OutlinedButton.icon(
                onPressed: () => controller.switchLightBulb(LightBulb.kitchen),
                icon: const Icon(Icons.lightbulb),
                label: const Text(''),
                iconAlignment: IconAlignment.end,
              ),
            ),
          ],
        ),
        onLoading: const Center(
          child: Text('LOADING...'),
        ),
        onError: (error) => const Center(
          child: Text('ERROR'),
        ),
        onEmpty: const Center(
          child: Text('EMPTY'),
        ),
      ),
    );
  }
}

CONTROLLER

enum LightBulb {
  kitchen,
  laundry,
}

class HousePlanController extends GetxController with StateMixin {
  var isKitchenSwitchedOn = true.obs;

  @override
  void onInit() {
    change(null, status: RxStatus.success());
    super.onInit();
  }

  void switchLightBulb(LightBulb lightBulb) {
    switch (lightBulb) {
      case LightBulb.kitchen:
        isKitchenSwitchedOn.toggle();
        break;
      default:
    }
  }
}

To Reproduce (bug) Steps to reproduce the behavior:

  1. Run the code
  2. Click on OutlinedButton
  3. All children will hide (expected only the green one)

Expected behavior Hide only the green widget using Stack()

  1. Change Stack() to Column() on HousePlanView
  2. Click on OutlinedButton
  3. Only one child is hidden (green one)

Screenshots Bug with Stack() Screenshot 2024-08-02 at 10 14 01 Screenshot 2024-08-02 at 10 14 08

Working with Column (or other widgets) Screenshot 2024-08-02 at 10 14 27 Screenshot 2024-08-02 at 10 14 32

Flutter Version:

flutter doctor -v
[✓] Flutter (Channel stable, 3.22.3, on macOS 14.5 23F79 darwin-arm64, locale en-BR)
    • Flutter version 3.22.3 on channel stable at /Users/thiagodelmotte/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b0850beeb2 (2 weeks ago), 2024-07-16 21:43:41 -0700
    • Engine revision 235db911ba
    • Dart version 3.4.4
    • DevTools version 2.34.3

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
    • Android SDK at /Users/thiagodelmotte/Library/Android/sdk
    • Platform android-35, build-tools 35.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15F31d
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2024.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314)

[✓] VS Code (version 1.91.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.94.0

[✓] Connected device (7 available)
    • sdk gphone arm64 (mobile)           • emulator-5554                        • android-arm64  • Android 11 (API 30) (emulator)
    • iPhone SE (3rd generation) (mobile) • A5672C57-DA48-4749-88BD-29F5E639528E • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-5
      (simulator)
    • iPhone 15 Pro Max (mobile)          • F398281B-23A6-42A3-9FA4-ABC30B730E36 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-5
      (simulator)
    • iPad Pro 13-inch (M4) (mobile)      • CC2569A5-800A-417F-A6D4-331FB8AEBF85 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-5
      (simulator)
    • macOS (desktop)                     • macos                                • darwin-arm64   • macOS 14.5 23F79 darwin-arm64
    • Mac Designed for iPad (desktop)     • mac-designed-for-ipad                • darwin         • macOS 14.5 23F79 darwin-arm64
    • Chrome (web)                        • chrome                               • web-javascript • Google Chrome 127.0.6533.89

[✓] Network resources
    • All expected network resources are available.

Getx Version:

  get:
    dependency: "direct main"
    description:
      name: get
      sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
      url: "https://pub.dev"
    source: hosted
    version: "4.6.6"

Describe on which device you found the bug: All devices, but tested:

  • iPhone 15 Pro Max
  • Android Medium Phone API 30
  • macOS
  • Chrome

Thank you very much for opening this issue, I haven't had the opportunity to run your repro code yet, but just by taking a quick look, I can identify the cause of the problem.

You are using a return const SizedBox.shrink(); inside a Stack (a widget that allows overlapping of its children). This is a problem that many don't realize, but there is a huge difference between doing this in a column, where this would be acceptable, or in a Stack (where this should NEVER be done).

How to solve this problem?

Well, there is a widget in Flutter that is universal, and aims to mitigate this type of problem, working with Column, or Stack, it is Visibility. If you change your code to something like this:

              Obx(() {
                return Visibility(
                  visible: controller.isKitchenSwitchedOn.value,
                  child: Positioned(
                    top: 50,
                    left: 50,
                    child: Container(
                      width: 120,
                      height: 120,
                      color: Colors.green,
                    ),
                  ),
                );
              }),

It should work.

I hope this helps, and let me know if this solved your problem.

jonataslaw avatar Aug 11 '24 21:08 jonataslaw

Hi @jonataslaw ,

That's not the real problem, in fact I'm not using const SizedBox.shrink(); in my real code, it was just to illustrate here and it ended up going wrong.

Anyway, I had also tested Visibility() and with IF without SizedBox.shrink(); and even so all the Widgets on the screen disappeared.

I understand that this is a real bug, because I tried to simulate it separately in several simpler and more complex ways and in all of them I had the same result.

If you can't simulate it, even removing SizedBox.shrink();, let me know so I can help you show you the problem.

For now I've worked around the problem by using the opacity property to hide what I need on the screen, but it's not an ideal solution.

Thanks

Thank you for your response.

Can the issue be reproduced with the code provided in version 4?

I just tested the code provided in version 5, and I can reproduce the problem using SizedBox.shrink(); and I can't reproduce uit using Visibility.

jonataslaw avatar Aug 12 '24 19:08 jonataslaw

Yes, I'm using 4.6.6. Using the code below, if I change Visible to False, everything disappears from Stack.

return Stack(
      children: [
        Positioned(
          top: 0,
          left: 0,
          child: Image.asset(
            asset,
          ),
        ),
        Obx(() {
          return const Visibility(
            visible: true,
            child: Positioned(
              top: 100,
              left: 100,
              child: SizedBox(
                width: 200,
                height: 200,
                child: Text('Test'),
              ),
            ),
          );
        }),
      ],
    );