Reputation: 7519
Edit:
I got a report that this is a duplicate of When the keyboard appears, the Flutter widgets resize. How to prevent this?. While this is related, it is a different issue. I want the keyboard to overlap the UI until it reaches the TextField that has focus. This is default behavior on Android
Original:
I am an Android developer and just started with Flutter. I wanted to create a log in screen. I wanted an image above the TextField
's. So I thought, I use a Stack
to have the image on the background and some TextField
's below.
The issue is that as soon as the keyboard appears, it pushes all content up. On Android, usually the keyboard only pushes up if necessary and only until it reaches the EditText
.
I tried setting resizeToAvoidBottomPadding
to false, but then nothing moves (of course) and the TextField
's get covered by the keyboard.
I remember from playing around with iOS in the past, this is default behavior, maybe I should reconsider my layout?
At the moment, I wrap it in a ListView
so that the user is able to scroll when the keyboard appears.
This is my layout (just for testing)
@override
Widget build(BuildContext context) {
this.context = context;
return new Scaffold(
key: _scaffoldKey,
body: new Stack(
children: <Widget>[loginImage(), new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[new TextField(), new TextField(),
new TextField(), new TextField(),
new TextField(), new TextField()],
)])
);
}
Upvotes: 18
Views: 64032
Reputation: 4360
It's 2025. Flutter has evolved much and so are the workarounds to fix this problem. For mobile apps Scaffold's resizeToAvoidBottomInset property is enough but for mobile web browsers the issue is different on iOS and Android.
For iOS web, the trick is to listen to didChangeMetrics and remove focus when keyboard is hidden by the Done button on the keyboard accessory view.
For android web, you have to set resizeToAvoidBottomInset to false but only for android web and not others.
I know this is confusing but the solution is indeed complex but it handles all scenarios. See this post which explains it step by step: https://cleancodestack.com/flutter-keyboard-issues-fix-ios-android-and-web/
Upvotes: 1
Reputation: 31
Set this on scaffold:
resizeToAvoidBottomInset: true
Use stack to set your background.
body: Stack(fit: StackFit.expand, children: <Widget>[
Opacity(
opacity: 0.5,
child: Image.asset('lib/assets/images/background3.jpg',
fit: BoxFit.cover)),
Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Header1(),
SizedBox(
height: 10,
),
Tittle("Welcome to Bitetat's live repots"),
Expanded(
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
Now you can enjoy nice background and your keyboard will not cover the fields and also scrollable.
Upvotes: 3
Reputation: 41
There also an alternate way instead of resizeToAvoidBottomInset
You can put the body of the Scaffold into SingleChildScrollView
and apply physics to NeverScrollableScrollPhysics()
.
Scaffold(
body: SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
child: Stack(
children: [ ........
Upvotes: 0
Reputation: 186
It is default functionality of the Flutter. so, if you set resizeToAvoidBottomInset: false
then you will lose the functionality of keeping your UI components above the keyboard.
To have a background image in your application
better way is to do it like this:
Container(
decoration: BoxDecoration(
color: primaryColor,
image: DecorationImage(image: AssetImage(AppImages.appBg)),
),
child: SafeArea(
child: Scaffold(
backgroundColor: Colors.transparent,
body: //All Ui code here//
),
),
),
It is necessary to set Scaffold's backgroundColor: Colors.transparent otherwise, you won't be able to see your background image.
Upvotes: 1
Reputation: 4678
I had this problem while setting autoFocus: true
in a CupertinoTextField()
and fixed it by setting resizeToAvoidBottomInset: false
in Scaffold()
.
resizeToAvoidBottomPadding
is deprecated now.
Use resizeToAvoidBottomInset
.
Upvotes: 57
Reputation: 3552
Also instead of Stack
I suggest you use ListView
. You could also on the other hand tryout SingleChildScrollView
(but you might have to add extra codes for implementation).
Happy Coding...
Upvotes: 4
Reputation: 7186
I think this does what you want. The biggest problem is that you chose to use a Stack. A stack is only used if you want to stack things on top of each other. In this case you don't want that. Placing it in a Column and filling the open space with an Expanded (This Widget expands to usable space and pushes everything down) is the way I do it. I don't say it's the best way (Only 2 weeks of flutter experience). But it's a way. I hope it helps!
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
body: new Column(
children: <Widget>[
new Center(
child: new Container(
height: 150.0,
width: 75.0,
color: Colors.red,
),
),
new Expanded(
child: new Container(),
),
new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new TextField(),
new TextField(),
new TextField(),
new TextField(),
new TextField(),
new TextField()
],
),
],
),
),
);
}
}
Upvotes: 3