How can I get the height of the BottomNavigationBar of a Scaffold in Flutter? I know there is MediaQuery.of(context).size to get a screen size. Is there a similar method for BottomNavigationBar?
Container(
width: MediaQuery.of(context).size.width,
height: kBottomNavigationBarHeight,
child: Scaffold(
backgroundColor: Colors.transparent,
body: null,
bottomNavigationBar: BottomNavigationBar()
)
)
This will create a Scaffold with enough room only for the BottomNavigationBar widget.
kBottomNavigationBarHeight is a constant, and can be found in the constants.dart file.
For getting size of widget you can use key field
final key = GlobalKey();
... set key field of widget
double height = key.currentContext.size.height;
If you want to know height of bottomNavigationBar in one of the children's screens of main Scaffold with bottomNavigationBar you can use MediaQuery:
final bottomPadding = MediaQuery.of(context).padding.bottom;
Bottom padding from MediaQuery, in addition of SafeArea, takes into account bottomNavigationBar's height.
More detailed:
#override
Widget build(BuildContext context) {
final bottomPadding = MediaQuery.of(context).padding.bottom; // From here you will get only SafeArea padding.
return Scaffold(
body: PageView(
children: const [
// But in build() method of each of these screens you will get
// SafeArea padding with bottomNavigationBar height
// just by calling MediaQuery.of(context).padding.bottom;
FirstScreen(),
SecondScreen(),
ThirdScreen(),
FourthScreen(),
],
),
bottomNavigationBar: MyBottomNavigationBar(),
);
}
I tried and for android i used kBottomNavigationBarHeight and for ios i think the height is 90 pixel.. so i declared the height in my constant file such as double btmNavigationBarHeight = Platform.isAndroid ? kBottomNavigationBarHeight : 90;
According to dosc: https://api.flutter.dev/flutter/material/NavigationBar/height.html
If null, NavigationBarThemeData.height is used. If that is also null, the default is 80
Related
I have a Text widget that sometimes can be fully displayed, sometimes not, depending on the widgets around.
If there is not enough space to fully display the widget, I want the widget to not show at all, I don't want it to show partially like with the overflow attribute.
If you know a way to do this, thanks.
LayoutBuilder to the rescue for you!
Builds a widget tree that can depend on the parent widget's size.
Reference
Try this! Play around with the allowedTextHeightInPixels value to see how it works.
/// Breakpoint or condition to WHEN should we display the Text widget
const allowedTextHeightInPixels = 150.0;
/// Test height for the [Text] widget.
const givenTextHeightByScreenPercentage = 0.3;
class ResponsiveTextWidget extends StatelessWidget {
const ResponsiveTextWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: LayoutBuilder(
builder: (context, constraints) {
print('Text height in pixels: ${constraints.maxHeight * givenTextHeightByScreenPercentage}');
return Column(
children: [
Container(
color: Colors.red,
height: constraints.maxHeight * 0.5,
),
if (constraints.maxHeight * givenTextHeightByScreenPercentage > allowedTextHeightInPixels)
const SizedBox(
child: Text(
'Responsive Me',
style: TextStyle(fontSize: 15.0),
),
),
Container(
color: Colors.blue,
height: constraints.maxHeight * 0.2,
),
],
);
},
),
),
);
}
}
I don't know why you need to do this but i thing overflow is good enough for most case, you can also use Fittedbox to scale the text with the box with no redundant space.
In case you still want do it, you need to find the RenderBox of that specific widget, which will contain its global position and rendered size from BuildContext. But BuildContext can be not exist if the widget is not rendered yet.
If by "fully displayed" you mean that, for example, you have a SingleChildScrollView and only half of your Text widget is visible, you can try out this library :
https://pub.dev/packages/visibility_detector.
You can retrieve the visible percentage of your widget with the method visibilityInfo.visibleFraction.
Code
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Search Families'),
centerTitle: true,
),
backgroundColor: StaticEntry.backColor,
body: Center(
child: FractionallySizedBox(
widthFactor: 0.8,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SearchInput(onSubmitHandler: onSubmit),
SizedBox(
height: 300,
),
resultList.isNotEmpty
? Container( // <---------------- Container that I am using to wrap the list view widget
height: 400, // <---------------- fixed height I am setting on the container that is wrapped around the ListView widget
child: ListView.builder( // <---------------- ListView widget
itemCount: 20,
itemBuilder: (context, index) {
return Text('Heyyyy!');
},
),
)
: SizedBox()
],
),
),
),
),
);
}
Problem
In the above code, as I have pointed using arrows, I am wrapping a ListView widget in a Container and assigning a fixed height to that Container since ListView widgets has an infinite height by default.
The problem with this approach is, since that height I am providing to the container is a fixed height, the layout breaks on devices with small viewport heights, while it works fine with devices that has a large viewport height.
So what I am trying to figure out is, how can I set a height to that Container that works on all devices without breaking the layout? (I am trying to make that height as maximum as possible without making the app break on smaller devices.)
(While researching about this, I came across this stack overflow link and according to that link, I tried wrapping the ListView widget with a Flexible widget and set the shrinkWrap property of the ListView widget to true. This did not work and it caused my ListView widget and the other widget to gain as much space as possible between them and pushed my ListView widget to the bottom of the screen.)
I want to get the width of a FlatButton in an horizontal ListView but i only can get Width: Infinity.
I can get width in an isolated FlatButton succesfully, but when the FlatButton is inside of a ListView i cannot, but i don't know why. Could you help me to get the width of a FlatButton when it is inside a ListView?
Thanks.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter App'),
),
body: Container(
height: 70.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
_flatButtonStoreWidth(),
],
),
),
);
}
Widget _flatButtonStoreWidth (){
return FlatButton (
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
double _width = constraints.maxWidth;
print('Width: $_width');
return Text('This is a FlatButton');
},
),
onPressed: (){},
);
}
To get width of the object in ListView you are supposed to:
Give widget a GlobalKey.
When build is complete, access the context through the GlobalKey.
Using context you can get size by context.size.
You can get width from Size object.
Following is the working code for your reference:
Widget _flatButtonStoreWidth() {
GlobalKey globalKey = GlobalKey();
WidgetsBinding.instance.addPostFrameCallback((_) {
double _width = globalKey.currentContext.size.width;
print('Width: $_width');
});
return FlatButton(
key: globalKey,
child: Text('This is a FlatButton'),
onPressed: () {},
);
}
I hope this helps, in case of any doubt please comment. In case this this answer helps you please accept and up-vote it.
That's because the ListView with a horizontal axis has an infinite width. You'll have to provide a width for each FlatButton.
FlatButton gets its size from the parent. In this case the parent provides an infinite width. Therefore you should size the button yourself
I'm trying to set dynamic sizes to the widgets that I implement in my application, I'm currently using:
MediaQuery.of(context).size.width/height
which gives you the size of the screen, but I need the widgets to be based on the size of the scaffolding body and not the full screen
You can user a Builder for your Scaffold:
return Scaffold(
appBar: AppBar(),
body: Builder(
builder: (context) {
return Stack(
children: <Widget>[
And then:
bodyHeight = MediaQuery.of(context).size.height - Scaffold.of(context).appBarMaxHeight
At least, I found the solution in that way.
Yes you can do it with a layoutBuilder widget. Check this:
https://medium.com/#KarthikPonnam/flutter-layoutbuilder-widget-1-b09fd1e6907f
Here is the how you can get Scaffold body height correctly
Firstly, get the AppBar height. You need to use variable for it.
var appBar = AppBar(
title: Text('Testing'),
);
Now, follow the below code [which is basically=> Total Height - AppBar's height - Padding present on the top(App status bar's height )]
final bodyHeight = MediaQuery.of(context).size.height -
-appBar.preferredSize.height -
MediaQuery.of(context).padding.top
How to use it? Let say you have Column with 2 child
Column(children: [
Container(
height: bodyHeight * 0.7,
child: ...,
),
Container(
height: bodyHeight * 0.3,
child: ...,
),
],
)
You could also subtract the height of the appbar from MediaQuery.of(context).size.height
Just simply do this to get the size (height in this case) of your Scaffold Body alone.
final fullHeight = MediaQuery.of(context).size.height;
final appBar = AppBar(); //Need to instantiate this here to get its size
final appBarHeight = appBar.preferredSize.height + MediaQuery.of(context).padding.top;
final scaffoldBodyHeight = fullHeight - appBarHeight;
Note: appBarHeight is the addition of the height of the appBar and the height of the device status bar.
scaffoldBodyHeight is the height of your scaffold body!
I am trying to understand the SafeArea widget in Flutter.
SafeArea code added to Flutter Gallery app here in github show top:false and bottom:false everywhere. Why do these need to be set false in these cases?
SafeArea is basically a glorified Padding widget. If you wrap another widget with SafeArea, it adds any necessary padding needed to keep your widget from being blocked by the system status bar, notches, holes, rounded corners, and other "creative" features by manufacturers.
If you are using a Scaffold with an AppBar, the appropriate spacing will be calculated at the top of the screen without needing to wrap the Scaffold in a SafeArea and the status bar background will be affected by the AppBar color (Red in this example).
If you wrap the Scaffold in a SafeArea, then the status bar area will have a black background rather than be influenced by the AppBar.
Here is an example without SafeArea set:
Align(
alignment: Alignment.topLeft, // and bottomLeft
child: Text('My Widget: ...'),
)
And again with the widget wrapped in a SafeArea widget:
Align(
alignment: Alignment.topLeft, // and bottomLeft
child: SafeArea(
child: Text('My Widget: ...'),
),
)
You can set a minimum padding for edges not affected by notches and such:
SafeArea(
minimum: const EdgeInsets.all(16.0),
child: Text('My Widget: ...'),
)
You can also turn off the safe area insets for any side:
SafeArea(
left: false,
top: false,
right: false,
bottom: false,
child: Text('My Widget: ...'),
)
Setting them all to false would be the same as not using SafeArea. The default for all sides is true. Most of the time you will not need to use these settings, but I can imagine a situation where you have a widget that fills the whole screen. You want the top to not be blocked by anything, but you don't care about the bottom. In that case, you would just set bottom: false but leave the other sides to their default true values.
SafeArea(
bottom: false,
child: myWidgetThatFillsTheScreen,
)
Supplemental code
In case you want to play around more with this, here is main.dart:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: BodyWidget(),
),
);
}
}
class BodyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topLeft,
child: SafeArea(
left: true,
top: true,
right: true,
bottom: true,
minimum: const EdgeInsets.all(16.0),
child: Text(
'My Widget: This is my widget. It has some content that I don\'t want '
'blocked by certain manufacturers who add notches, holes, and round corners.'),
),
);
}
}
When you wrap a widget A in a safe area, you are asking to the framework "Please, keep my widget A away from the device's UI navigation and notches".
The arguments 'top, bottom, right and left' are used to tell to the framework if you want him to avoid the device's intrusions from that sides specifically.
For example: if you put your widget A inside a safe area in the top of the screen and sets the "top" argument to false, it will be cropped by the iPhone's X and Pixel 3's notches.
SafeArea is a widget that sets its child by enough padding to avoid intrusions by the operating system and improve the user interface.
import 'package:flutter/material.dart';
class SafeArea extends StatefulWidget {
#override
_SafeAreaState createState() => _SafeAreaState();
}
class _SafeAreaState extends State<SafeArea> {
#override
Widget build(BuildContext context) {
MediaQueryData mediaQueryData=MediaQuery.of(context);
double screenWidth = mediaQueryData.size.width;
var bottomPadding=mediaQueryData.padding.bottom;
return Padding(
padding: EdgeInsets.only(bottom: bottomPadding),
child: Scaffold(
body: new Container(
),
),
); }}
Without using SafeArea in iPhone 12 pro max
With using SafeArea
Code snippet using SafeArea
SafeArea(
child: Text('Your Widget'),
)