Skip to content

Transparency/Opacity destroys depth/z-translation #113346

@SaadArdati

Description

@SaadArdati

Steps to Reproduce

  1. Open the sample app below.
  2. Observe how the stacks are FLATTENED.
  3. Go back to the code and remove the Opacity widget on line 80 marked with a // DELETE ME comment.
  4. Hot restart and observe again. The stack of containers now has proper depth perception.

Expected results: Z transforms are preserved when an image exists in a widget tree.

Actual results: Z transforms get completely flattened all the way to the top of the widget tree.

Code sample
import 'dart:math';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  late final AnimationController _orientationController = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 2),
  )..addListener(() {
      setState(() {});
    });

  late final AnimationController _depthController = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 1),
  )..addListener(() {
      setState(() {});
    });

  Widget? rainbow;

  @override
  void initState() {
    super.initState();
    _orientationController.repeat();
    _depthController.repeat(reverse: true);

    rainbow = genRainbow();
  }

  @override
  void dispose() {
    _orientationController.dispose();
    _depthController.dispose();
    super.dispose();
  }

  Color genColor() {
    // return Colors.red;
    final Random random = Random();
    return Color.fromRGBO(
      random.nextInt(255),
      random.nextInt(255),
      random.nextInt(255),
      1,
    );
  }

  /// A recursive function to create a nested widget tree of rainbow colors.
  Widget genRainbow([int index = 0]) {
    if (index > 5) {
      
      // DELETE ME
      return Opacity(
        opacity: 1,
        child: Image.network(
          'https://storage.googleapis.com/cms-storage-bucket/0dbfcc7a59cd1cf16282.png',
          fit: BoxFit.contain,
        ),
      );
    }

    // As we go deeper, the size needs to get smaller.
    final size = 200 - index * 20.0;

    rainbow = AnimatedBuilder(
      animation: _depthController,
      builder: (context, child) {
        return Transform(
          transform: Matrix4.identity()
            ..setEntry(3, 2, 0.001)
            ..translate(
              0.0,
              0.0,
              _depthController.value * -30,
            ),
          transformHitTests: false,
          alignment: FractionalOffset.center,
          child: child,
        );
      },
      child: Container(
        width: size,
        height: size,
        alignment: Alignment.center,
        decoration: BoxDecoration(
          border: Border.all(color: Colors.black),
          color: genColor(),
        ),
        child: genRainbow(index + 1),
      ),
    );

    return rainbow!;
  }

  @override
  Widget build(BuildContext context) {
    final double angle = ((1 - _orientationController.value) * 360) / 180 * pi;

    final double x = sin(angle) * 0.5;
    final double y = cos(angle) * 0.5;

    final double rotX = cos(x) * sin(y);
    final double rotY = -sin(x);

    final matrix = Matrix4.identity()
      ..setEntry(3, 2, 0.001)
      ..rotateX(rotX)
      ..rotateY(rotY);

    return Scaffold(
      body: Transform(
        transform: matrix,
        alignment: Alignment.center,
        child: Center(child: rainbow),
      ),
    );
  }
}
Logs

https://gist.github.com/SwissCheese5/45a58a9dd1b630afc0fa2ca0700d2164

saadardati@Saads-MacBook-Pro flutter_bug_transparency_breaks_transforms % flutter analyze
Analyzing flutter_bug_transparency_breaks_transforms...                 
No issues found! (ran in 1.1s)
saadardati@Saads-MacBook-Pro flutter_bug_transparency_breaks_transforms % flutter doctor -v
[✓] Flutter (Channel stable, 3.3.3, on macOS 12.6 21G115 darwin-arm, locale en-LB)
    • Flutter version 3.3.3 on channel stable at /Users/saadardati/Desktop/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 18a827f393 (2 weeks ago), 2022-09-28 10:03:14 -0700
    • Engine revision 5c984c26eb
    • Dart version 2.18.2
    • DevTools version 2.15.0

[!] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
    • Android SDK at /Users/saadardati/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 14.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14A400
    • CocoaPods version 1.11.3

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

[✓] Android Studio (version 2020.3)
    • 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 11.0.10+0-b96-7249189)

[✓] IntelliJ IDEA Ultimate Edition (version 2022.2.3)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 70.2.5
    • Dart plugin version 222.4345.14

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

[✓] Connected device (3 available)
    • Saad’s iPhone (mobile) • 00008110-000555941151801E • ios            • iOS 16.0 20A362
    • macOS (desktop)        • macos                     • darwin-arm64   • macOS 12.6 21G115 darwin-arm
    • Chrome (web)           • chrome                    • web-javascript • Google Chrome 106.0.5249.103

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.
Screen.Recording.2022-10-12.at.8.37.16.PM.mp4
Screen.Recording.2022-10-12.at.8.36.44.PM.mov

This issue seems to be scoped to immediate children. It does not happen in stacks I think, but I am not sure.

Here it is with more animations and controls to help better visualize what is going on. In this case, for some reason that i could NOT replicate, ANY images produced this phenomena. Removing all Opacity, but keeping the direct Image.network widgets produces this, but i could only replicate this in a reproducible sample with Opacity only.

Screen.Recording.2022-10-12.at.8.41.41.PM.mp4

Metadata

Metadata

Labels

P1High-priority issues at the top of the work listengineflutter/engine related. See also e: labels.found in release: 3.3Found to occur in 3.3found in release: 3.5Found to occur in 3.5frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-engineOwned by Engine team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions