Skip to content

Instantly share code, notes, and snippets.

@jamilsaadeh97
Last active October 22, 2025 18:01
Show Gist options
  • Save jamilsaadeh97/98fa12eb07038a4be724c103c42a038b to your computer and use it in GitHub Desktop.
Save jamilsaadeh97/98fa12eb07038a4be724c103c42a038b to your computer and use it in GitHub Desktop.
Bottom sheet with text fields
import 'package:flutter/material.dart';
// This is an example of a bottom sheet with a text field inside a tab
// and a footer with another text field.
// Please use a tablet simulator on landscape mode to better see the issue.
// When the text field of tab 1 is pressed and focused, the keyboard appears and
// resizes the bottom sheet correctly. However, the footer go over the whole content of tab 1 which
// causes the user to not see what's being written.
// I came up with several workarounds but I don't feel it's the right way to handle that kind of situation.
// It really felt too "hacky"
// My current workarounds:
// 1- I tried switching the visibility off of the footer when the tab1's text field is focused.
// 2- I tried addind a "resizeToAvoidBottomInset: false" to the Scaffold of the bottom sheet and
// adding a listener to the focus node of the footer text field.
// Whenever it is focused, I set the bottom padding to MediaQuery.viewInsetsOf(context).bottom
// This way, only when the footer text field is focused, the footer is "lifted up" to avoid the keyboard.
// When the tab1's text field is focused, nothing is being resized.
// Any suggestions or pointers would be appreciated. Thank you
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.dark(),
home: const MyHomePage(title: 'Bottom sheet demo'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _onPressed() {
showModalBottomSheet(
context: context,
useSafeArea: true,
isScrollControlled: true,
isDismissible: true,
builder: (context) => SomeBottomSheet(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: _onPressed,
child: Text("Open bottom sheet"),
),
],
),
),
);
}
}
class SomeBottomSheet extends StatelessWidget {
const SomeBottomSheet({super.key});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(child: SomeBody()),
SomeFooter(),
],
),
),
),
),
);
}
}
class SomeBody extends StatelessWidget {
const SomeBody({super.key});
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Column(
children: [
TabBar(
tabs: [
Tab(text: "Tab 1"),
Tab(text: "Tab 2"),
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TabBarView(children: [Tab1Content(), Tab2Content()]),
),
),
],
),
);
}
}
class Tab1Content extends StatelessWidget {
const Tab1Content({super.key});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
spacing: 20,
children: [
TextField(decoration: InputDecoration(labelText: "Some label")),
ElevatedButton(onPressed: () {}, child: Text("Submit")),
],
),
);
}
}
/// Demonstration purposes only - close to my real use case
class Tab2Content extends StatelessWidget {
const Tab2Content({super.key});
@override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: 20,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (context, index) =>
ListTile(title: Text("Item ${index + 1}")),
);
}
}
class SomeFooter extends StatelessWidget {
const SomeFooter({super.key});
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
color: Colors.black45,
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(decoration: InputDecoration(labelText: "Footer input")),
SizedBox(height: 75), // This is a placeholder for any content.
ElevatedButton(onPressed: () {}, child: Text("Footer button")),
],
),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment