[iOS] - UiKitView behind a full-screen BottomSheet receives taps on iOS
- Dominant language
- Dart
- Stars
- 179k
- Forks
- 31.1k
- PR merge metrics
- PR metrics pending
Description
### Steps to reproduce
1. Create a Flutter app with a CustomScrollView.
2. Add a SliverAppBar with a UiKitView in actions (e.g., right-side circle button).
3. Add a list below the app bar (e.g., SliverList with multiple items).
4. Add a bottom-aligned row of multiple UiKitViews.
5. Wrap list items with GestureDetector that shows a full-screen ModalBottomSheet (isScrollControlled: true).
6. Run on iOS (Simulator or device).
7. Tap the UiKitView inside the bottom sheet at a location overlapping the UiKitView behind.
### Expected results
No need to listen in the bottom sheet, and some rectangular shapes(Masked UikitView) should not be shown in the bottom sheet.
### Actual results
The UiKitView behind the bottom sheet also receives the tap.
Taps “pass through” the overlaying Flutter bottom sheet.
### Code sample
Main dart
```
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: SliverAppBarDemo(),
);
}
}
class SliverAppBarDemo extends StatelessWidget {
const SliverAppBarDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
CustomScrollView(
slivers: [
SliverAppBar(
toolbarHeight: 100,
backgroundColor: Colors.blue,
centerTitle: true,
floating: false,
pinned: false,
expandedHeight: 70,
leading: const SizedBox(width: 50),
title: const Text(
"Header Title",
style: TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
actions: [
Container(
margin: const EdgeInsets.only(right: 12),
width: 50,
height: 50,
color: Colors.red,
child: UiKitView(
key: const ValueKey('plusButton_glass_view'),
viewType: "circle_container_view",
creationParamsCodec: const StandardMessageCodec(),
),
),
],
),
SliverPadding(
padding: const EdgeInsetsDirectional.only(bottom: 80),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return GestureDetector(
onTap: () {
showModalBottomSheet(
useSafeArea: true,
context: context,
isScrollControlled: true, // makes full screen
backgroundColor: Colors.amber.shade50,
builder: (context) {
return SizedBox(
height: MediaQuery.of(context).size.height, // full height
child: Column(
children: [
AppBar(
automaticallyImplyLeading: false,
title: Text("Item $index Details"),
backgroundColor: Colors.blue,
),
Expanded(
child: Center(
child: Text(
"Full bottom sheet content for Item $index",
style: const TextStyle(fontSize: 18),
),
),
),
],
),
);
},
);
},
child: Container(
height: 50,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 16),
color: index.isEven ? Colors.grey[200] : Colors.white,
child: Text("Item $index"),
),
);
},
childCount: 50,
),
),
),
// SliverPadding(
// padding: const EdgeInsetsDirectional.only(bottom: 80),
// sliver: SliverList(
// delegate: SliverChildBuilderDelegate((context, index) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Container(
// height: 50,
// alignment: Alignment.centerLeft,
// padding: const EdgeInsets.symmetric(horizontal: 16),
// color: index.isEven ? Colors.grey[200] : Colors.white,
// child: Text("Item $index"),
// ),
// ],
// );
// }, childCount: 50),
// ),
// ),
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
color: Colors.pink,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.only(right: 24),
width: 50,
height: 50,
color: Colors.orange,
child: UiKitView(
key: const ValueKey('plusButton_glass_view'),
viewType: "circle_container_view",
creationParamsCodec: const StandardMessageCodec(),
),
),
Container(
margin: const EdgeInsets.only(right: 24),
width: 50,
height: 50,
color: Colors.teal,
child: UiKitView(
key: const ValueKey('plusButton_glass_view'),
viewType: "circle_container_view",
creationParamsCodec: const StandardMessageCodec(),
),
),
Container(
margin: const EdgeInsets.only(right: 24),
width: 50,
height: 50,
color: Colors.greenAccent,
child: UiKitView(
key: const ValueKey('plusButton_glass_view'),
viewType: "circle_container_view",
creationParamsCodec: const StandardMessageCodec(),
),
),
],
),
),
)
],
),
),
);
}
}
```
AppDelgate
```
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let factory = PlusButtonViewFactory()
registrar(forPlugin: "circle_container_view_plugin")?
.register(factory, withId: "circle_container_view")
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
```
ButtonCode
```
class PlusButtonViewFactory: NSObject, FlutterPlatformViewFactory {
func create(
withFrame frame: CGRect,
viewIdentifier viewId: Int64,
arguments args: Any?
) -> FlutterPlatformView {
return SwiftUIViewWrapper(rootView: PlusButtonView(), frame: frame)
}
}
class SwiftUIViewWrapper: NSObject, FlutterPlatformView {
private var hostingController: UIHostingController
init(rootView: T, frame: CGRect) {
hostingController = UIHostingController(rootView: AnyView(rootView))
hostingController.view.frame = frame
hostingController.view.backgroundColor = .clear
}
func view() -> UIView {
return hostingController.view
}
}
struct PlusButtonView: View {
var body: some View {
if #available(iOS 26.0, *) {
GlassEffectContainer {
Button(action: {}) {
Image(systemName: "plus")
.font(.system(size: 20)) // Increase icon size directly
.frame(width: 24, height: 24)
.foregroundColor( .white)
.padding()
}
.frame(width: 48, height: 48)
.background(
Color(hex: 0xFF15_8C5B)
)
.clipShape(Circle())
.glassEffect(
.regular.interactive()
)
}
} else {
// Fallback on earlier versions
}
}
}
extension Color {
init(hex: Int, opacity: Double = 1) {
self.init(
.sRGB,
red: Double((hex >> 16) & 0xff) / 255,
green: Double((hex >> 08) & 0xff) / 255,
blue: Double((hex >> 00) & 0xff) / 255,
opacity: opacity
)
}
}
```
### Screenshots or Video
https://github.com/user-attachments/assets/21770ef7-b32a-48a4-a939-0823711cceb6
### Logs
Logs
```console
[Paste your logs here]
```
### Flutter Doctor output
Doctor output
```console
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, 3.37.0-0.1.pre, on macOS 26.0.1 25A362 darwin-arm64, locale en-IN)
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 26.0)
[✓] Chrome - develop for the web
[✓] Connected device (4 available)
```
Contributor guide
Research direction
Start with the provided Main dart reproduction and the AppDelegate and ButtonCode platform-view implementations, then run the sample on iOS using the listed Flutter and Xcode versions. Trace the full-screen bottom sheet and overlapping UiKitView interaction; done means taps and rectangular platform-view content do not pass through or appear behind the sheet.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart, ios, swift
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100