Annoying Keyboard Overlaps: Understanding Flutter’s Padding, vs ViewPadding vs ViewInsets. Oh! My

Syed Abdul Basit
6 min readJul 21, 2023

--

Handling layouts when the device’s keyboard is visible has always been a challenge for me. Without careful consideration, the keyboard could obscure a significant portion of my app’s UI, leading to an unsatisfactory user experience.

A common situation might involve me filling the whole screen with a stack, giving a hero image the top 50%, a text input the bottom 10%, and maybe a scrollable list of comment that remaining 40%. Stacks are powerful, So before long, my UI would be looking good, and I’d be excited about to start testing it out.

I’d tap on the text input. And suddenly, the keyboard appears and covers half the screen, including the very text input it’s supposed to power. This is not what I wanted.

Understanding everything requires getting cozy with the MediaQuery class.

Let’s dive into the details.

First of all, just like many classes in flutter, the value you get back from the MediaQuery.of(context) is actually a media query data object. This is similar to how theme.of(context) returns a ThemeData object. And within that Media Query data class, which is flush with useful information, are three attributes of particular interest for our request. They are:

  • MediaQuery.of(context).Padding
  • MediaQuery.of(context).ViewPadding
  • MediaQuery.of(context).ViewInsets

These variables are well named and easy to keep straight.

Just Kidding! 😆

They’re impossible to keep straight, which is why we are writing this article.

For ViewInsets. The documentation says that:

“The part of the display that are completely obscured by system UI typically by the device’s keyboard.”

According to me about ViewInsets:

“The area of the screen that is reserved for system UI elements. It includes things like the status bar at the top of the screen and the navigation bar (soft or physical) at the bottom of the screen. These insets define the safe area where your app’s content should be placed to avoid overlapping with system UI elements”

That’s pretty straight forward

In my head, I distinguished this from the other two by thinking about how you have to press keys into type. ViewInsets is for the keyboard.

For Padding. The documentation says that:

“The part of the display that is partially obscured by system UI typically by the hardware display ‘notches’ or the system’s status bar.”

According to me about Padding:

“The padding on each of the four sides (top, right, bottom, left) of the current screen. This padding value is calculated by Flutter based on the device’s physical insets (such as the status bar height) and the padding set by the operating system (e.g., notch area padding on devices with a notch).”

import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Accessing the MediaQueryData to get the padding information
MediaQueryData mediaQueryData = MediaQuery.of(context);

return Scaffold(
appBar: AppBar(
title: Text('Responsive Widget'),
),
body: Padding(
// Use the mediaQueryData.padding to add spacing on all sides
padding: mediaQueryData.padding,
child: Center(
child: Text(
'Hello, Flutter!',
style: TextStyle(fontSize: 24.0),
),
),
),
);
}
}

For ViewPadding. The documentation says that:

“The part of the display that is partially obscured by system UI typically by the hardware display ‘notches’ or the system’s status bar.”

According to me about ViewPadding:

any additional padding imposed by the system on the content of the screen. It is similar to viewInsets but only accounts for the padding that the system adds around the content.

import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Accessing the MediaQueryData to get the viewInsets and viewPadding
MediaQueryData mediaQueryData = MediaQuery.of(context);

return Scaffold(
appBar: AppBar(
title: Text('Responsive Widget'),
),
body: Padding(
// Use the combined viewInsets and viewPadding to add spacing on all sides
padding: EdgeInsets.fromLTRB(
mediaQueryData.viewInsets.left + mediaQueryData.viewPadding.left,
mediaQueryData.viewInsets.top + mediaQueryData.viewPadding.top,
mediaQueryData.viewInsets.right + mediaQueryData.viewPadding.right,
mediaQueryData.viewInsets.bottom + mediaQueryData.viewPadding.bottom,
),
child: Center(
child: Text(
'Hello, Flutter!',
style: TextStyle(fontSize: 24.0),
),
),
),
);
}
}

Which sounds very similar na.

So what’s the difference between padding and viewPadding?

Well not much unless the device keyboard is showing up, then things get interesting.

An example of an IOS device reserves a small area to detect swipes that raise the system tray.
But what happens to those pixels when the keyboard is up?

They are no longer reserved for this purpose. They’re doing keyboard things now. And so when the keyboard is raised, the value for padding.bottom is consumed by viewInsets.bottom and drops to zero.
This makes sense.
But if you’ve used padding.bottom to position things within a stack, then the keyboard arrival will shift your UI down several pixels toward the keyboard. Also not what you want.

So, what’s a developer to do if they want consistent positioning regardless of what misbehavior the keyboard is getting up to. That’s viewPadding.

The difference between padding and viewPadding is that, is a keyboard comes along and tramples all over the edge of your device, viewPadding remembers what was.

What about SafeAreas, you might be wondering?

By using SafeArea along with MediaQueryData.viewInsets and MediaQueryData.viewPadding, your app's content will be appropriately positioned on the screen, considering the specific device's screen size and system UI elements, providing a consistent and user-friendly experience across different devices and orientations.

Remember that SafeArea is just one way to handle system insets and padding; you can also manually calculate and apply the padding as shown in the previous example if you need more fine-grained control over the layout.

Well, if you wrap everything in a SafeArea, then most of the numbers stay pinned to zero. That’s the job of the SafeArea, after all, except viewPadding.bottom and viewInset.bottom only when the keyboard is showing.

import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Accessing the MediaQueryData to get the viewInsets and viewPadding
MediaQueryData mediaQueryData = MediaQuery.of(context);

return Scaffold(
appBar: AppBar(
title: Text('Responsive Widget'),
),
body: SafeArea(
// Use the combined viewInsets and viewPadding to add spacing on all sides
child: Padding(
padding: EdgeInsets.fromLTRB(
mediaQueryData.viewInsets.left + mediaQueryData.viewPadding.left,
mediaQueryData.viewInsets.top + mediaQueryData.viewPadding.top,
mediaQueryData.viewInsets.right + mediaQueryData.viewPadding.right,
mediaQueryData.viewInsets.bottom + mediaQueryData.viewPadding.bottom,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Welcome to My App',
style: TextStyle(fontSize: 24.0),
),
SizedBox(height: 20.0),
ElevatedButton(
onPressed: () {
// Your button's action here
},
child: Text('Click Me'),
),
],
),
),
),
);
}
}

To Review

ViewInsets: represents an area fully obscured by the system, basically the keyboard.

Padding: represents areas partially obscured by the system, basically notches.

What about when a keyboard consumes the space behind the notches?

Padding drops to zero but viewPadding maintains its value.

Dealing with these concepts might be tricky to remember at first, but don’t worry; you’re in good company! As developers, it takes practice and experience to master these aspects of Flutter layout management. 😇

For More Details checkout below link

--

--