-
Notifications
You must be signed in to change notification settings - Fork 28.9k
Description
Steps to reproduce
This is very likely related to (but not identical to): #110431 this issue is not limited to scroll behavior and shows a lag of >1 frame.
- Create a simple flutter app that has a button and shows something on the screen when the button is pressed
- Run the app (in debug or release mode, it doesn't matter)
- Use some precision measurement tools like an FSR sensor and a photodiode (some results below), or, record a video (attached below) at an extremely high frame rate to get a clear indication of touch input -> screen render latency
Why this matters
- Game performance. Input lag / touch / display latency is an important contributing factor to the experience of playing a game.
- Research (my case). Research, especially neuroscience, but also behavioural and others, requires precise understanding of timing, and low latency along the entire pipeline is critical to even begin to report results of reaction times, or associate it with brain events (usually sampled at 1000Hz)
My use case
I'm aware this is probably a niche case, but I think it could have a big impact.
I'm creating a research tool for group dynamics research. This is a growing field with advancements like EEG and MEG hyperscanning. Often experiments have to be coded each time for different labs and devices.
Other options like psychopy don't work on mobile devices, and are definitely not geared towards group research, although psychopy does allow for precise timing control on a single device.
I've spent a lot of time getting this off the ground as part of my PhD project and I've built a Dart native library wrapper for handling network coordination and communication, but this issue has me panicking a little bit because I'm not sure that as it stands, flutter can fit the bill.
Summary
I'm going to be doing experiments using iPads. If I can use flutter, I will be publishing it as a platform for other researchers, and will also be at the core of several of my publications.
Flutter has the potential to be a useful, and maybe even the go-to tool for a bunch of types of research, but not if low latency (at least close as possible to the native device level) can be achieved.
Expected results
Same latency as a swiftUI app, or interacting with native UI elements on the device, also should be similar to android and linux, (obviously with device differences).
Actual results
Several frames of latency are introduced, regularly 80+ milliseconds on a real device, similar results are observed using the simulator.
Code sample
Code sample
For a more complete example (attempting different input detection methods, and frame scheduling, see: https://github.com/NexusDynamic/button_display_latency )
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(
home: const TestScreen(),
);
}
}
class TestScreen extends StatefulWidget {
const TestScreen({super.key});
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
bool _showFlash = false;
void _onButtonPressed() {
setState(() {
_showFlash = true;
});
Future.delayed(const Duration(milliseconds: 20), () {
if (mounted) {
setState(() {
_showFlash = false;
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Listener(
onPointerDown: (_) => _onButtonPressed(),
child: Container(
width: 150,
height: 150,
color: Colors.blue,
alignment: Alignment.center,
child: const Text(
'Press Me',
style: TextStyle(color: Colors.white),
),
),
),
const SizedBox(height: 50),
Container(
width: 100,
height: 100,
color: _showFlash ? Colors.red : Colors.transparent,
),
],
),
),
);
}
}
Compare this to the swiftUI version:
// ContentView.swift
// uitest
import SwiftUI
extension View {
func onTouchDown(perform action: @escaping () -> Void) -> some View {
self.simultaneousGesture(
DragGesture(minimumDistance: 0)
.onChanged { _ in
action()
}
)
}
}
struct ContentView: View {
@State private var showRectangle = false
@State private var useTouchDown = true
@Environment(\.colorScheme) var colorScheme
private func triggerRectangle() {
showRectangle = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) {
showRectangle = false
}
}
var body: some View {
VStack {
Toggle("Use TouchDown", isOn: $useTouchDown)
.padding()
Button(action: useTouchDown ? {} : triggerRectangle) {
Text("Tap me")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.onTouchDown {
if useTouchDown {
triggerRectangle()
}
}
Rectangle()
.fill(showRectangle ? (colorScheme == .dark ? Color.white : Color.black) : Color.clear)
.frame(width: 200, height: 200)
.padding()
}
.padding()
}
}
#Preview {
ContentView()
}
Screenshots or Video
Screenshots / Video demonstration
Flutter (exact MWE as above) on an iPad M3 Pro:
PXL_20250617_111446337_flutter.mp4
Swift (exact swift MWE as above) on iPad M3 Pro:
PXL_20250617_095533582_ipad_swift.mp4
Comprehensive example (linked above), on a Pixel 7a (Android 16 BP31.250523.006):
IMG_0002_crop_android.mov
Comprehensive example (Arch linux on a Razer Blade Stealth (2017) with touchscreen):
IMG_0003_crop_linux.mov
Comprehensive example (iOS simulator):
flutter_demo_latency.mp4
Some results (which have, a small native-lib + network stack overhead ~<1ms). Theses were recorded using a FSR sensor placed on top of the on-screen button (t=0) and sending a network packet (reference point) and then showing a square on screen captured by a photodiode). The implementation for the test is here: https://github.com/NexusDynamic/liblsl.dart/tree/main/packages/liblsl_test
These are the results for two iPads (one sender with FSR sensor, both consumers with photodiode):
Logs
Logs
# N/A
Flutter Doctor output
Doctor output
flutter doctor -v
[✓] Flutter (Channel main, 3.33.0-1.0.pre.516, on macOS 15.5 24F74 darwin-arm64, locale en-US) [6.9s]
• Flutter version 3.33.0-1.0.pre.516 on channel main at /Users/au662726/development/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision e2e543dbd7 (2 days ago), 2025-06-15 02:17:28 -0400
• Engine revision e2e543dbd7
• Dart version 3.9.0 (build 3.9.0-235.0.dev)
• DevTools version 2.48.0-dev.0
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [5.4s]
• Android SDK at /Users/au662726/Library/Android/sdk
• Emulator version 35.4.9.0 (build_id 13025442) (CL:N/A)
• Platform android-36, build-tools 36.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.5+-13047016-b750.29)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 16.4) [7.6s]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 16F6
• CocoaPods version 1.16.2
[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome) [15ms]
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Android Studio (version 2024.3) [15ms]
• 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 21.0.5+-13047016-b750.29)
[✓] VS Code (version 1.102.0-insider) [12ms]
• VS Code at /Applications/Visual Studio Code - Insiders.app/Contents
• Flutter extension version 3.113.20250603
[✓] Connected device (2 available) [12.4s]
• xxx iPad (wireless) (mobile) • xxx-xxxx • ios • iOS 18.1 22B83
• macOS (desktop) • macos • darwin-arm64 • macOS 15.5 24F74 darwin-arm64
! Error: Browsing on the local area network for xxx iPad (2). Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources [697ms]
• All expected network resources are available.
! Doctor found issues in 1 category.