Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] PlatformView tap coordinates mapping incorrectly when in a scroll view #146570

Closed
frankkulak opened this issue Apr 10, 2024 · 5 comments · Fixed by flutter/engine#52532
Assignees
Labels
a: platform-views Embedding Android/iOS views in Flutter apps c: regression It was better in the past than it is now f: scrolling Viewports, list views, slivers, etc. found in release: 3.19 Found to occur in 3.19 found in release: 3.22 Found to occur in 3.22 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-android Android applications specifically r: fixed Issue is closed as already fixed in a newer version team-android Owned by Android platform team triaged-android Triaged by Android platform team

Comments

@frankkulak
Copy link

Steps to reproduce

  1. Create an app with at least two tabs, using IndexedStack to switch between them.
  2. In those tabs, place a PlatformView (such as WebViewWidget from webview_flutter) in each.
  3. In one of the tabs, place the PlatformView in a fixed-height SizedBox, following a sibling fixed-height SizedBox, in a Column, in a SingleChildScrollView.
  4. Observe that taps on the PlatformView in the scroll view are mapped incorrectly:
    1. They are offset on the y axis by the height of the sibling above them in the column.
    2. When scrolling down, they are still mapping to the same place as if you hadn't scrolled at all.

Additional notes:

  • Our app had no issue with this structure on Flutter 3.13. We upgraded to 3.19, and started observing this issue on Android only.
  • We believe it is an issue with Flutter itself rather than a specific package (such as webview_flutter) because we also observe this behavior on other PlatformViews like Google Maps.

Expected results

Tapping on a PlatformView should always register the tap at the correct coordinates for where the PlatformView is currently being rendered.

Actual results

It is taking the coordinates of where the user tapped on the viewport, and using those exact coordinates in the PlatformView.

Code sample

The provided code sample is the absolute minimum we believe is required for the issue to occur: there needs to be an IndexedStack, at least two PlatformViews, and any PlatformView that doesn't fill the entire screen's height will have the issue.

Note: Forcing the PlatformView to refresh at least once will temporarily "solve" the issue. We did this by setting the key of the webview, waiting for it to load, and then changing the key one time. However, upon switching tabs and going back to the broken page, the issue comes back. To show this, we added a button to this sample that will change the key of the webview.

main.dart

Code sample
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:webview_test/html_content.dart';

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

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

  @override
  State<ScrollIssueTestApp> createState() => _ScrollIssueTestAppState();
}

class _ScrollIssueTestAppState extends State<ScrollIssueTestApp> {
  int _selectedTab = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: IndexedStack(
            index: _selectedTab,
            children: [
              const _ProblemWebViewPage(),
              _PlaceholderWebViewPage(),
            ],
          ),
        ),
        bottomNavigationBar: BottomNavigationBar(
          showUnselectedLabels: true,
          type: BottomNavigationBarType.fixed,
          currentIndex: _selectedTab,
          onTap: ((index) {
            setState(() {
              _selectedTab = index;
            });
          }),
          items: const [
            BottomNavigationBarItem(
              icon: Icon(Icons.local_fire_department_outlined),
              label: 'Problem',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.abc),
              label: 'Other',
            ),
          ],
        ),
      ),
    );
  }
}

class _ProblemWebViewPage extends StatefulWidget {
  const _ProblemWebViewPage();

  @override
  State<_ProblemWebViewPage> createState() => _ProblemWebViewPageState();
}

class _ProblemWebViewPageState extends State<_ProblemWebViewPage> {
  late final WebViewController _controller;
  static const double _webviewHeight = 850;
  String _webviewKey = 'default_key';

  @override
  void initState() {
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted).then((_) {
        _controller.loadHtmlString(problemPageContent);
      });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(
            height: 100,
            width: double.infinity,
            child: Center(
              child: ElevatedButton(
                onPressed: () {
                  setState(() {
                    _webviewKey = 'new_key';
                  });
                },
                child: const Text('tap to "fix" webview'),
              ),
            ),
          ),
          SizedBox(
            height: _webviewHeight,
            width: double.infinity,
            child: WebViewWidget(
              key: Key(_webviewKey),
              controller: _controller,
            ),
          ),
        ],
      ),
    );
  }
}

class _PlaceholderWebViewPage extends StatelessWidget {
  _PlaceholderWebViewPage();

  final WebViewController _controller = WebViewController()
    ..loadHtmlString(placeholderPageContent);

  @override
  Widget build(BuildContext context) {
    return WebViewWidget(controller: _controller);
  }
}

html_content.dart (Sample webview content that clearly shows the issue.)

Code sample
const problemPageContent = r'''
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Flutter Sample Problem</title>
</head>

<body>
  <div class="end-marker">
    <p>top of webview</p>
  </div>
  <div id="color-list"></div>
  <div class="end-marker">
    <p>bottom of webview</p>
  </div>
  <script>
    (() => {
      const colorList = document.getElementById("color-list");
      for (let i = 0; i < 16; ++i) {
        const colorCell = document.createElement("button");
        colorList.appendChild(colorCell);

        colorCell.innerText = `Button #${i} (Tapped: None)`;
        colorCell.classList.add("color-cell");
        colorCell.style.backgroundColor = "#" + (15 - i).toString(16).repeat(6);
        colorCell.style.color = i > 7 ? "white" : "black";
        colorCell.onclick = () => {
          const buttons = document.querySelectorAll("button");
          buttons.forEach((button, j) => {
            button.innerText = `Button #${j} (Tapped: #${i})`
          });
        };
      }
    })();
  </script>
</body>
<style>
  body,
  p {
    margin: 0;
  }

  .end-marker {
    width: 100%;
    height: 25px;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #a9f1fb;
  }

  .color-cell {
    width: 100%;
    height: 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
  }
</style>

</html>
''';

const placeholderPageContent = r'''
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Placeholder</title>
</head>

<body>
  <h1>Placeholder Webview</h1>
</body>

</html>
''';

Screenshots or Video

Screenshots / Video demonstration FlutterIssue
FlutterWebviewIssue.mov

Logs

For logs, see file:

FlutterLogs.txt

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):

[✓] Flutter (Channel stable, 3.19.5, on macOS 13.6.4 22G513 darwin-x64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.2)
[✓] VS Code (version 1.81.1)
[✓] Connected device (4 available)
[✓] Network resources

• No issues found!
@darshankawar darshankawar added the in triage Presently being triaged by the triage team label Apr 11, 2024
@darshankawar
Copy link
Member

Thanks for the report. I was able to replicate this on latest versions.

stable, master flutter doctor -v
[!] Flutter (Channel stable, 3.19.5, on macOS 12.2.1 21D62 darwin-x64, locale
    en-GB)
    • Flutter version 3.19.5 on channel stable at
      /Users/dhs/documents/fluttersdk/flutter
    ! Warning: `flutter` on your path resolves to
      /Users/dhs/Documents/Fluttersdk/flutter/bin/flutter, which is not inside
      your current Flutter SDK checkout at
      /Users/dhs/documents/fluttersdk/flutter. Consider adding
      /Users/dhs/documents/fluttersdk/flutter/bin to the front of your path.
    ! Warning: `dart` on your path resolves to
      /Users/dhs/Documents/Fluttersdk/flutter/bin/dart, which is not inside your
      current Flutter SDK checkout at /Users/dhs/documents/fluttersdk/flutter.
      Consider adding /Users/dhs/documents/fluttersdk/flutter/bin to the front
      of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 300451adae (4 days ago), 2024-03-27 21:54:07 -0500
    • Engine revision e76c956498
    • Dart version 3.3.3
    • DevTools version 2.31.1
    • If those were intentional, you can disregard the above warnings; however
      it is recommended to use "git" directly to perform update checks and
      upgrades.

[!] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    ! Flutter recommends a minimum Xcode version of 13.
      Download the latest version or update via the Mac App Store.
    • CocoaPods version 1.11.2

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

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

[✓] Connected device (5 available)
    • SM G975F (mobile)       • RZ8M802WY0X • android-arm64   • Android 11 (API 30)
    • Darshan's iphone (mobile)  • 21150b119064aecc249dfcfe05e259197461ce23 •
      ios            • iOS 14.4.1 18D61
    • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729     •
      ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
    • macOS (desktop)            • macos                                    •
      darwin-x64     • Mac OS X 10.15.4 19E2269 darwin-x64
    • Chrome (web)               • chrome                                   •
      web-javascript • Google Chrome 98.0.4758.80

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

! Doctor found issues in 1 category.

[!] Flutter (Channel master, 3.22.0-7.0.pre.14, on macOS 12.2.1 21D62
    darwin-x64, locale en-GB)
    • Flutter version 3.22.0-7.0.pre.14 on channel master at
      /Users/dhs/documents/fluttersdk/flutter
    ! Warning: `flutter` on your path resolves to
      /Users/dhs/Documents/Fluttersdk/flutter/bin/flutter, which is not inside
      your current Flutter SDK checkout at
      /Users/dhs/documents/fluttersdk/flutter. Consider adding
      /Users/dhs/documents/fluttersdk/flutter/bin to the front of your path.
    ! Warning: `dart` on your path resolves to
      /Users/dhs/Documents/Fluttersdk/flutter/bin/dart, which is not inside your
      current Flutter SDK checkout at /Users/dhs/documents/fluttersdk/flutter.
      Consider adding /Users/dhs/documents/fluttersdk/flutter/bin to the front
      of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 74b65d4e4c (4 hours ago), 2024-04-09 21:26:14 -0400
    • Engine revision eaf73cd39c
    • Dart version 3.5.0 (build 3.5.0-36.0.dev)
    • DevTools version 2.34.1
    • 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 30.0.3)
    • Android SDK at /Users/dhs/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 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 13C100
    • CocoaPods version 1.11.2

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

[✓] IntelliJ IDEA Ultimate Edition (version 2021.3.2)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 65.1.4
    • Dart plugin version 213.7228

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

[✓] Connected device (3 available)
    • Darshan's iphone (mobile) • 21150b119064aecc249dfcfe05e259197461ce23 • ios
      • iOS 15.3.1 19D52
    • macOS (desktop)           • macos                                    •
      darwin-x64     • macOS 12.2.1 21D62 darwin-x64
    • Chrome (web)              • chrome                                   •
      web-javascript • Google Chrome 109.0.5414.119

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

! Doctor found issues in 1 category.
      
[!] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    ! Flutter recommends a minimum Xcode version of 13.
      Download the latest version or update via the Mac App Store.
    • CocoaPods version 1.11.2

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

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

[✓] Connected device (5 available)
    • SM G975F (mobile)       • RZ8M802WY0X • android-arm64   • Android 11 (API 30)
    • Darshan's iphone (mobile)  • 21150b119064aecc249dfcfe05e259197461ce23 •
      ios            • iOS 14.4.1 18D61
    • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729     •
      ios            • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
    • macOS (desktop)            • macos                                    •
      darwin-x64     • Mac OS X 10.15.4 19E2269 darwin-x64
    • Chrome (web)               • chrome                                   •
      web-javascript • Google Chrome 98.0.4758.80

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

! Doctor found issues in 1 category.



@darshankawar darshankawar added platform-android Android applications specifically a: platform-views Embedding Android/iOS views in Flutter apps has reproducible steps The issue has been confirmed reproducible and is ready to work on team-android Owned by Android platform team found in release: 3.19 Found to occur in 3.19 found in release: 3.22 Found to occur in 3.22 f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. and removed in triage Presently being triaged by the triage team labels Apr 11, 2024
@reidbaker reidbaker added the c: regression It was better in the past than it is now label Apr 11, 2024
@mariamhas
Copy link

From customer: This seems to only seems to happen with 3.19 and is blocking the ability to upgrade to the latest version of Flutter for their production app

@reidbaker reidbaker added P2 Important issues not at the top of the work list triaged-android Triaged by Android platform team labels Apr 18, 2024
@AnikethFitPass
Copy link

Any updates I am also facing the same issue

@gmackall
Copy link
Member

gmackall commented May 2, 2024

Confirmed that this reproduces on master, and is fixed with a clean revert of flutter/engine#49268.

@gmackall
Copy link
Member

gmackall commented May 2, 2024

Looks like we could potentially fix this with https://developer.android.com/reference/android/view/MotionEvent#offsetLocation(float,%20float). Input events still seem to be verified after having their location offset.

Just need to determine the required offset.

auto-submit bot pushed a commit to flutter/engine that referenced this issue May 14, 2024
Fixes flutter/flutter#146570, which tracks a regression from #49268 regarding platform view inputs in some specific cases.

This PR translates the input event location to be the same as the location we calculated before #49268, returning to the previous behavior, while maintaining the input event's verified status (I checked this manually with the `InputManager`).

Tested manually with the reproduction in the linked issue.

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
@gmackall gmackall self-assigned this May 14, 2024
@darshankawar darshankawar added the r: fixed Issue is closed as already fixed in a newer version label May 15, 2024
flutteractionsbot pushed a commit to flutteractionsbot/engine that referenced this issue May 22, 2024
Fixes flutter/flutter#146570, which tracks a regression from flutter#49268 regarding platform view inputs in some specific cases.

This PR translates the input event location to be the same as the location we calculated before flutter#49268, returning to the previous behavior, while maintaining the input event's verified status (I checked this manually with the `InputManager`).

Tested manually with the reproduction in the linked issue.

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: platform-views Embedding Android/iOS views in Flutter apps c: regression It was better in the past than it is now f: scrolling Viewports, list views, slivers, etc. found in release: 3.19 Found to occur in 3.19 found in release: 3.22 Found to occur in 3.22 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-android Android applications specifically r: fixed Issue is closed as already fixed in a newer version team-android Owned by Android platform team triaged-android Triaged by Android platform team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants