flutter / devtools

Performance tools for Flutter
https://flutter.dev/docs/development/tools/devtools/
BSD 3-Clause "New" or "Revised" License
1.56k stars 321 forks source link

WidgetInspector finds wrong widget #6170

Open tvolkert opened 4 years ago

tvolkert commented 4 years ago

Steps to reproduce

Run the following app:

sample app ```dart import 'dart:ui' show window; import 'package:flutter/material.dart'; void main() { runApp(BugReport()); } class BugReport extends StatelessWidget { @override Widget build(BuildContext context) { return Localizations( locale: Locale('en', 'US'), delegates: [ DefaultWidgetsLocalizations.delegate, DefaultMaterialLocalizations.delegate, ], child: WidgetInspector( selectButtonBuilder: (BuildContext context, VoidCallback onPressed) { return FloatingActionButton( child: const Icon(Icons.search), onPressed: onPressed, mini: true, ); }, child: MediaQuery( data: MediaQueryData.fromWindow(window), child: Navigator( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute( settings: settings, builder: (BuildContext context) { return DefaultTextStyle( style: TextStyle(color: Colors.black), child: Home(), ); }, ); }, ), ), ), ); } } class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ DecoratedBox( decoration: BoxDecoration(color: Color(0xffc8c8bb)), child: Padding( padding: EdgeInsets.all(8), child: Align( alignment: Alignment.centerLeft, child: SizedBox( height: 60, child: GestureDetector( onTap: () => _openModalDialog(context), child: Container( width: 150, alignment: Alignment.center, decoration: BoxDecoration(border: Border.all()), child: Text('Open Modal Dialog'), ), ), ), ), ), ), Expanded( child: ColoredBox(color: Colors.white), ), ], ); } } Future _openModalDialog(BuildContext context) { showGeneralDialog( context: context, barrierDismissible: false, barrierLabel: 'Dismiss', barrierColor: const Color(0x80000000), pageBuilder: ( BuildContext context, Animation animation, Animation secondaryAnimation, ) { return DefaultTextStyle( style: TextStyle(color: Colors.black), child: Align( alignment: Alignment.topCenter, child: DecoratedBox( decoration: BoxDecoration( border: Border.all(color: Color(0xff999999)), color: Color(0xfff7f5ee), ), child: Padding( padding: EdgeInsets.all(8), child: SizedBox( width: 460, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox( height: 200, child: Container(color: Colors.cyan), ), SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ GestureDetector( onTap: () => Navigator.of(context).pop(), child: Container( width: 66, height: 22, alignment: Alignment.center, decoration: BoxDecoration(border: Border.all()), child: Text('OK'), ), ), ], ), ], ), ), ), ), ), ); }, ); } ```

Then:

  1. Click "Open Modal Dialog" (this will activate the widget inspector rather than launch the dialog)
  2. Click "Open Modal Dialog" again to open the modal dialog
  3. Click the magnifying glass select button in the lower left of the app
  4. Click the upper part of the cyan box in the modal dialog -- the part that is vertically aligned with the "Open Modal Dialog" button.

Expected behavior

You expect the widget inspector to detect and highlight the cyan box (the Container or its SizedBox parent).

Actual behavior

The widget inspector detects and highlights the Align widget that houses the "Open Modal Dialog" box. This widget is (a) under a modal barrier and cannot receive input events, and (b) painted over and is obscured by the cyan box in the modal dialog -- and so the widget inspector should not be able to select it.

ezgif-7-543401d178cc

Other info

I have variants of this happen quite often, and it completely removes the utility of the widget inspector when it happens, so marking as P3.

Version info ``` [✓] Flutter (Channel master, 1.21.0-7.0.pre, on Mac OS X 10.15.3 19D76, locale en-US) • Flutter version 1.21.0-7.0.pre at /Users/tvolkert/project/flutter/flutter • Framework revision d261f1ef58 (8 days ago), 2020-08-03 00:59:36 -0400 • Engine revision 083282e33b • Dart version 2.10.0 (build 2.10.0-2.0.dev 365525432a) [✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3) • Android SDK at /Users/tvolkert/Library/Android/sdk • Platform android-28, build-tools 28.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.6) • Xcode at /Applications/Xcode_11.6.app/Contents/Developer • Xcode 11.6, Build version 11E708 • CocoaPods version 1.9.2 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 48.0.2 • Dart plugin version 193.7361 • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) [✓] Connected device (3 available) • macOS (desktop) • macos • darwin-x64 • Mac OS X 10.15.3 19D76 • Web Server (web) • web-server • web-javascript • Flutter Tools • Chrome (web) • chrome • web-javascript • Google Chrome 84.0.4147.105 ```
devoncarew commented 4 years ago

cc @jacob314

jacob314 commented 4 years ago

Looks like we are doing a bad job at determining which widget is visually on top of which widget in the render tree for that case. To get it right 100% of the time we'd need to use some mechanism for the inspector hit testing that more exactly matches what is rendered on the device. Ideally hit testing would be based on determining which render object(s) actually painted the specific pixel. As a workaround if you hit issues like that, you can take advantage of the fact that the inspector will select a render object if you select right at the edge of the render object even if the inspector doesn't think the render object is visually in front of the other widget. If you hold down the mouse while using an emulator it is fairly easy to see the bounding box for each render object and move the mouse until you are right on top of the desired widget.

tvolkert commented 4 years ago

The framework already has hit testing APIs that it uses e.g. when the user taps or clicks. How much information do the debugging tools get from their hit testing routines that the framework's hit testing wouldn't provide? I wonder if a good long-term solution would be to just beef up the framework APIs as needed.

jacob314 commented 4 years ago

Doing debugger hit testing correctly as part of the regular hit testing mechanism would require significant breaking changes to the hit testing api.

For example, hitTestSelf and hitTestChildren would need to take an additional argument to indicate that a hit testing algorithm suitable for debugging tools should be used instead of the regular one. For example, the logic to absorb a hit doesn't make sense when using a debugging tool. Implementing this fully would require a major breaking change and it would likely require non-trivial changes in many render objects.

An interesting middle ground could be to bias the inspector debugger specific hit testing mechanism to bias towards results that are descendants of the hit test result returned by the regular algorithm. That might be able to cover up cases where the inspector hit testing algorithm is wrong about what widget is in front.

pedromassangocode commented 3 years ago

Reproducible on latest master channel.

gif

flutter doctor -v ``` [✓] Flutter (Channel master, 1.22.0-10.0.pre.356, on Mac OS X 10.15.6 19G2021 x86_64, locale en) • Flutter version 1.22.0-10.0.pre.356 at /Users/pedromassango/dev/SDKs/flutter_master • Framework revision c412fd9967 (4 hours ago), 2020-09-24 22:47:03 -0700 • Engine revision 435db234e4 • Dart version 2.11.0 (build 2.11.0-161.0.dev) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1) • Android SDK at /Users/pedromassango/Library/Android/sdk • Platform android-30, build-tools 30.0.1 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 12.0) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 12.0, Build version 12A7209 • CocoaPods version 1.9.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [!] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) [✓] IntelliJ IDEA Community Edition (version 2020.2.2) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 49.0.4 • Dart plugin version 202.7319.5 [✓] VS Code (version 1.48.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.14.1 [✓] Connected device (4 available) • iPhone 11 Pro Max (mobile) • 7A82F29E-E49E-4B3C-8609-1570361DBC17 • ios • com.apple.CoreSimulator.SimRuntime.iOS-14-0 (simulator) • macOS (desktop) • macos • darwin-x64 • Mac OS X 10.15.6 19G2021 x86_64 • Web Server (web) • web-server • web-javascript • Flutter Tools • Chrome (web) • chrome • web-javascript • Google Chrome 85.0.4183.121 ! Doctor found issues in 1 category. Process finished with exit code 0 ```
AleksandarSavic95 commented 3 years ago

This is still an issue, Jun 2021. Please fix it, it would bring so much ease to the dev experience.

tvolkert commented 2 years ago

Still an issue as of Oct 2021.

This would fit nicely in Flutter's developer experience theme of work.

danagbemava-nc commented 1 year ago

Reproduces on the latest versions of flutter using the code sample and steps provided above.

https://user-images.githubusercontent.com/88313112/205890705-57b236b1-2627-4006-a9ba-c16f4b3bee0d.mov

updated sample ```dart import 'dart:ui' show window; import 'package:flutter/material.dart'; void main() { runApp(const BugReport()); } class BugReport extends StatelessWidget { const BugReport({super.key}); @override Widget build(BuildContext context) { return Localizations( locale: const Locale('en', 'US'), delegates: const [ DefaultWidgetsLocalizations.delegate, DefaultMaterialLocalizations.delegate, ], child: WidgetInspector( selectButtonBuilder: (BuildContext context, VoidCallback onPressed) { return FloatingActionButton( onPressed: onPressed, mini: true, child: const Icon(Icons.search), ); }, child: MediaQuery( data: MediaQueryData.fromWindow(window), child: Navigator( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute( settings: settings, builder: (BuildContext context) { return const DefaultTextStyle( style: TextStyle(color: Colors.black), child: Home(), ); }, ); }, ), ), ), ); } } class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ DecoratedBox( decoration: const BoxDecoration(color: Color(0xffc8c8bb)), child: Padding( padding: const EdgeInsets.all(8), child: Align( alignment: Alignment.centerLeft, child: SizedBox( height: 60, child: GestureDetector( onTap: () => _openModalDialog(context), child: Container( width: 150, alignment: Alignment.center, decoration: BoxDecoration(border: Border.all()), child: const Text('Open Modal Dialog'), ), ), ), ), ), ), const Expanded( child: ColoredBox(color: Colors.white), ), ], ); } } Future _openModalDialog(BuildContext context) { return showGeneralDialog( context: context, barrierDismissible: false, barrierLabel: 'Dismiss', barrierColor: const Color(0x80000000), pageBuilder: ( BuildContext context, Animation animation, Animation secondaryAnimation, ) { return DefaultTextStyle( style: const TextStyle(color: Colors.black), child: Align( alignment: Alignment.topCenter, child: DecoratedBox( decoration: BoxDecoration( border: Border.all(color: const Color(0xff999999)), color: const Color(0xfff7f5ee), ), child: Padding( padding: const EdgeInsets.all(8), child: SizedBox( width: 460, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox( height: 200, child: Container(color: Colors.cyan), ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ GestureDetector( onTap: () => Navigator.of(context).pop(), child: Container( width: 66, height: 22, alignment: Alignment.center, decoration: BoxDecoration(border: Border.all()), child: const Text('OK'), ), ), ], ), ], ), ), ), ), ), ); }, ); } ```
flutter doctor -v ``` [✓] Flutter (Channel stable, 3.3.9, on macOS 13.0.1 22A400 darwin-arm, locale en-GB) • Flutter version 3.3.9 on channel stable at /Users/nexus/dev/sdks/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision b8f7f1f986 (2 weeks ago), 2022-11-23 06:43:51 +0900 • Engine revision 8f2221fbef • Dart version 2.18.5 • DevTools version 2.15.0 [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) • Android SDK at /Users/nexus/Library/Android/sdk • Platform android-33, build-tools 33.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 14.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 14B47b • CocoaPods version 1.11.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2021.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.13+0-b1751.21-8125866) [✓] VS Code (version 1.73.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.54.0 [✓] Connected device (4 available) • M2007J20CG (mobile) • 5dd3be00 • android-arm64 • Android 12 (API 31) • iPhone 14 Pro (mobile) • 4F72110C-F38B-4CF9-93C4-4D6042148D28 • ios • com.apple.CoreSimulator.SimRuntime.iOS-16-1 (simulator) • macOS (desktop) • macos • darwin-arm64 • macOS 13.0.1 22A400 darwin-arm • Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.94 [✓] HTTP Host Availability • All required HTTP hosts are available • No issues found! ``` ``` [!] Flutter (Channel master, 3.7.0-3.0.pre.35, on macOS 13.0.1 22A400 darwin-arm64, locale en-GB) • Flutter version 3.7.0-3.0.pre.35 on channel master at /Users/nexus/dev/sdks/flutters ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path. ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path. • Upstream repository https://github.com/flutter/flutter.git • Framework revision eaf6254488 (5 hours ago), 2022-12-06 00:39:23 -0500 • Engine revision 5d8530f790 • Dart version 2.19.0 (build 2.19.0-463.0.dev) • DevTools version 2.20.0 • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades. [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) • Android SDK at /Users/nexus/Library/Android/sdk • Platform android-33, build-tools 33.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 14.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 14B47b • CocoaPods version 1.11.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2021.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.13+0-b1751.21-8125866) [✓] VS Code (version 1.73.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.54.0 [✓] Connected device (4 available) • M2007J20CG (mobile) • 5dd3be00 • android-arm64 • Android 12 (API 31) • iPhone 14 Pro (mobile) • 4F72110C-F38B-4CF9-93C4-4D6042148D28 • ios • com.apple.CoreSimulator.SimRuntime.iOS-16-1 (simulator) • macOS (desktop) • macos • darwin-arm64 • macOS 13.0.1 22A400 darwin-arm64 • Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.94 [✓] HTTP Host Availability • All required HTTP hosts are available ! Doctor found issues in 1 category. ```
flutter-triage-bot[bot] commented 1 year ago

This issue is assigned but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!

flutter-triage-bot[bot] commented 1 year ago

This issue was assigned to @jacob314 but has had no status updates in a long time. To remove any ambiguity about whether the issue is being worked on, the assignee was removed.