// 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 createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, body: Stack( children: const [ FullStack(), ], ), ); } } class FullStack extends StatefulWidget { const FullStack({Key? key}) : super(key: key); @override State createState() => _FullStackState(); } class _FullStackState extends State { bool _safeArea = true; bool _fakeKeyboard = false; final focusNode = FocusNode(); @override void initState() { super.initState(); focusNode.requestFocus(); } @override Widget build(BuildContext context) { return Column( children: [ // 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: [ // 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: [ // 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: [ 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: [ 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: [ 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: [ 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: [ 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: [ const Text('RIGHT'), Text('Padding: ${padding.right}'), Text('ViewPadding: ${viewPadding.right}'), Text('ViewInsets: ${viewInsets.right}'), ], ); } }