Skip to content

Instantly share code, notes, and snippets.

@craiglabenz
Last active August 12, 2024 16:51
Show Gist options
  • Save craiglabenz/b0d016329a88863670d9e9a8f0789245 to your computer and use it in GitHub Desktop.
Save craiglabenz/b0d016329a88863670d9e9a8f0789245 to your computer and use it in GitHub Desktop.
Demonstrates Padding vs ViewPadding vs ViewInsets
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
final originalTheme = Theme.of(context);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Theme(
data: originalTheme.copyWith(
textTheme: originalTheme.textTheme.copyWith(
bodyMedium: originalTheme.textTheme.bodyMedium!.copyWith(
fontSize: 16,
),
),
),
child: const MyHomePage(title: 'Flutter Demo Home Page')),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: const <Widget>[
FullStack(),
],
),
);
}
}
class FullStack extends StatefulWidget {
const FullStack({Key? key}) : super(key: key);
@override
State<FullStack> createState() => _FullStackState();
}
class _FullStackState extends State<FullStack> {
bool _safeArea = true;
bool _fakeKeyboard = false;
final focusNode = FocusNode();
@override
void initState() {
super.initState();
focusNode.requestFocus();
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
// Uncomment this if you want to summon the real keyboard on mobile.
// const SizedBox(height: 100),
// Padding(
// padding: const EdgeInsets.symmetric(horizontal: 12),
// child: Row(
// children: <Widget>[
// Expanded(
// child: TextField(
// decoration: InputDecoration(
// filled: true,
// fillColor: Colors.grey[300],
// ),
// ),
// ),
// ],
// ),
// ),
Flexible(
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final keyboardTextStyle = Theme.of(context).textTheme.displayMedium;
late final EdgeInsets viewPadding;
late final EdgeInsets padding;
late final EdgeInsets positioning;
if (!_safeArea && !_fakeKeyboard) {
viewPadding = const EdgeInsets.symmetric(vertical: 20);
padding = const EdgeInsets.symmetric(vertical: 20);
positioning = EdgeInsets.zero;
} else if (_safeArea && !_fakeKeyboard) {
viewPadding = EdgeInsets.zero;
padding = EdgeInsets.zero;
positioning = const EdgeInsets.symmetric(vertical: 20);
} else if (!_safeArea && _fakeKeyboard) {
viewPadding = const EdgeInsets.symmetric(vertical: 20);
padding = const EdgeInsets.fromLTRB(0, 20, 0, 0);
positioning = EdgeInsets.zero;
} else {
// Have both
viewPadding = const EdgeInsets.fromLTRB(0, 0, 0, 20);
padding = EdgeInsets.zero;
positioning = const EdgeInsets.only(top: 20);
}
final MediaQueryData mq = MediaQuery.of(context).copyWith(
padding: padding,
viewPadding: viewPadding,
viewInsets: EdgeInsets.fromLTRB(
0,
0,
0,
_fakeKeyboard ? 300 : 0,
),
);
return Stack(
children: <Widget>[
// Top notch (heh)
Positioned(
left: mq.size.width / 4,
top: 10,
child: Container(
height: 5,
width: mq.size.width / 2,
color: Colors.grey[800],
),
),
// Bottom notch
!_fakeKeyboard
? Positioned(
left: mq.size.width / 4,
bottom: 10,
child: Container(
height: 5,
width: mq.size.width / 2,
color: Colors.grey[800],
),
)
: Container(),
Positioned(
bottom: mq.size.height / 2,
left: mq.size.width / 2.5,
child: Column(
children: <Widget>[
Text(
'Fake keyboard is ${_fakeKeyboard ? "REVEALED" : "HIDDEN"}',
style: Theme.of(context).textTheme.headlineSmall,
),
Switch(
value: _fakeKeyboard,
onChanged: (value) {
setState(() {
_fakeKeyboard = value;
});
},
),
Text(
'SafeArea is ${_safeArea ? "ON" : "OFF"}',
style: Theme.of(context).textTheme.headlineSmall,
),
Switch(
value: _safeArea,
onChanged: (value) {
setState(() {
_safeArea = value;
});
},
),
],
),
),
Positioned(
top: positioning.top,
left: mq.size.width / 2.2,
child: MediaQueryTopInfo(mediaQueryData: mq),
),
Positioned(
top: mq.size.height / 2.5 - mq.viewInsets.bottom / 2,
left: positioning.left,
child: MediaQueryLeftInfo(mediaQueryData: mq),
),
Positioned(
top: mq.size.height / 2.5 - mq.viewInsets.bottom / 2,
right: positioning.right,
child: MediaQueryRightInfo(mediaQueryData: mq),
),
Positioned(
bottom: positioning.bottom + mq.viewInsets.bottom,
left: mq.size.width / 2.2,
child: MediaQueryBottomInfo(mediaQueryData: mq),
),
_fakeKeyboard
? Positioned(
bottom: 0,
width: mq.size.width,
height: 300,
child: Container(
color: Colors.grey[300],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text('K', style: keyboardTextStyle),
Text('E', style: keyboardTextStyle),
Text('Y', style: keyboardTextStyle),
Text('B', style: keyboardTextStyle),
Text('O', style: keyboardTextStyle),
Text('A', style: keyboardTextStyle),
Text('R', style: keyboardTextStyle),
Text('D', style: keyboardTextStyle),
],
),
),
)
: Container()
],
);
},
),
)
],
);
}
}
class MediaQueryBottomInfo extends StatelessWidget {
const MediaQueryBottomInfo({Key? key, required this.mediaQueryData})
: super(key: key);
final MediaQueryData mediaQueryData;
@override
Widget build(BuildContext context) {
final viewInsets = mediaQueryData.viewInsets;
final viewPadding = mediaQueryData.viewPadding;
final padding = mediaQueryData.padding;
return Column(
children: <Widget>[
const Text('BOTTOM'),
Text('Padding: ${padding.bottom}'),
Text('ViewPadding: ${viewPadding.bottom}'),
Text('ViewInsets: ${viewInsets.bottom}'),
],
);
}
}
class MediaQueryTopInfo extends StatelessWidget {
const MediaQueryTopInfo({Key? key, required this.mediaQueryData})
: super(key: key);
final MediaQueryData mediaQueryData;
@override
Widget build(BuildContext context) {
final viewInsets = mediaQueryData.viewInsets;
final viewPadding = mediaQueryData.viewPadding;
final padding = mediaQueryData.padding;
return Column(
children: <Widget>[
const Text('TOP'),
Text('Padding: ${padding.top}'),
Text('ViewPadding: ${viewPadding.top}'),
Text('ViewInsets: ${viewInsets.top}'),
],
);
}
}
class MediaQueryLeftInfo extends StatelessWidget {
const MediaQueryLeftInfo({Key? key, required this.mediaQueryData})
: super(key: key);
final MediaQueryData mediaQueryData;
@override
Widget build(BuildContext context) {
final viewInsets = mediaQueryData.viewInsets;
final viewPadding = mediaQueryData.viewPadding;
final padding = mediaQueryData.padding;
return Column(
children: <Widget>[
const Text('LEFT'),
Text('Padding: ${padding.left}'),
Text('ViewPadding: ${viewPadding.left}'),
Text('ViewInsets: ${viewInsets.left}'),
],
);
}
}
class MediaQueryRightInfo extends StatelessWidget {
const MediaQueryRightInfo({Key? key, required this.mediaQueryData})
: super(key: key);
final MediaQueryData mediaQueryData;
@override
Widget build(BuildContext context) {
final viewInsets = mediaQueryData.viewInsets;
final viewPadding = mediaQueryData.viewPadding;
final padding = mediaQueryData.padding;
return Column(
children: <Widget>[
const Text('RIGHT'),
Text('Padding: ${padding.right}'),
Text('ViewPadding: ${viewPadding.right}'),
Text('ViewInsets: ${viewInsets.right}'),
],
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment