When clicking on the text input the web version of a Flutter app (iOS Safari), the soft keyboard covers the text input making it impossible to see what is being typed. (see gif below)
The expected behavior is that the text input would animate to remain visible above the soft keyboard, as it does in the iOS native version created by Flutter.
In Flutter 3.7, it appears that resizeToAvoidBottomInset
(which defaults to true
) should control this behavior:
if there is an onscreen keyboard displayed above the scaffold, the body can be resized to avoid overlapping the keyboard, which prevents widgets inside the body from being obscured by the keyboard.
However, in Safari on iOS this doesn't appear to be true.
Previous questions don't appear to fix this issue or introduce what appear to be unnecessary workarounds:
- Flutter TextFormField hidden by keyboard
- add
padding
to theTextField
- use
SingleScrollView
- add
- Flutter Keyboard makes textfield hide
- create custom animation
- add
SizedBox
belowTextField
- Flutter TextEditingController does not scroll above keyboard
- Flutter soft keyboard covering textfield and singlechildscrollview not working
View: soft keyboard obscures text input in Safari on iOS
Code:
import 'package:flutter/material.dart';
class TestScreen extends StatefulWidget {
const TestScreen({super.key});
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Chat')),
body: Column(
children: const [
Expanded(
child: Center(
child: Text('Send a message to start your conversation.'),
),
),
_MessageBar(),
],
),
);
}
}
class _MessageBar extends StatefulWidget {
const _MessageBar({Key? key}) : super(key: key);
@override
State<_MessageBar> createState() => __MessageBarState();
}
class __MessageBarState extends State<_MessageBar> {
late final TextEditingController _textController;
@override
Widget build(BuildContext context) {
return Material(
color: Colors.grey[200],
child: SafeArea(
child: Padding(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: Row(
children: [
Expanded(
child: TextFormField(
keyboardType: TextInputType.text,
maxLines: null,
autofocus: true,
controller: _textController,
decoration: const InputDecoration(
hintText: 'Type a message',
border: InputBorder.none,
focusedBorder: InputBorder.none,
contentPadding: EdgeInsets.all(8.0),
),
),
),
TextButton(
onPressed: () => _submitMessage(),
child: const Text('Send'),
)
],
),
),
),
);
}
@override
void initState() {
_textController = TextEditingController();
super.initState();
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
void _submitMessage() async {
final text = _textController.text;
if (text.isEmpty) {
return;
}
print({text});
_textController.clear();
}
}