What is PreferredSize after all? - flutter

I understand that it is used to adjust AppBar, but what is PreferredSize after all?
What is the use of PreferredSize widget in flutter?
The following text is found in the official documents, but I do not understand what it means.
https://api.flutter.dev/flutter/widgets/PreferredSize-class.html
It just advertises a preferred size which can be used by the parent.
The explanation in the official documentation is also limited to the AppBar, which I could not understand further.
I wrote the following code as a test, but the height of the green container was spread across the entire screen.
import 'package:flutter/material.dart';
void main() {
runApp(const _MyApp());
}
class _MyApp extends StatelessWidget {
const _MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: PreferredSize(
preferredSize: const Size.fromHeight(100.0),
child: Container(
width: 300,
color: Colors.green,
),
),
),
),
);
}
}

Here is the Short Details about it:
Preferred Size is a custom widget lets you allow to design your custom appbar for you with the same height, width, elevation and feel similar to Appbar.
Sometimes you want to create tabs or more effective design for your appbar then you can create a customChild for your appBar with the help of PreferredSizeWidget.

The size this widget would prefer if it were otherwise unconstrained.
In many cases it's only necessary to define one preferred dimension.
For example the [Scaffold] only depends on its app bar's preferred
height. In that case implementations of this method can just return
Size.fromHeight(myAppBarHeight).

Related

(Flutter) Is it possible to make bottomSheet of Scaffold transparent?

I've recently developed comment view below the detail posts.
Like the image I attached, I'd like to show images for each comment but the image Container should be transparent to see the last comment.
But I think Scaffold doesn't allow bottomSheet to have transparent children.
Are there anyone having an idea to solve this problem?
class PostDetail extends StatelessWidget {
final int maxRenderImgCnt = 4;
final Post post;
PostDetail(this.post);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar( ... ),
body: SingleChildScrollView( ... ),
bottomSheet: CommonTextField(onTap: null, editTarget: null),
You can wrap the widget with an opacity widget but there is also another way which is more efficient even for changing it later, that is the ThemeData widget:
bottomSheetTheme: BottomSheetThemeData(
backgroundColor: Colors.black.withOpacity(0),
),

How to modify Scaffold widget for the whole app

I have a big app and there's multi files with same scaffold tap action to hide the keyboard.
Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Container(
///Textfields
),
),
),
);
Is there way to edit Scaffold widget for the whole app?
short answer, you can not customize your scaffold for the whole app because each scaffold has its own body, but you can customize the theme of the app such as the text colour or the font for the whole app on the main screen using the materialApp widget.
-If you are willing to make something fixed in the whole app like the same app bar or the navbar for the whole app that's possible and you have to create a separate screen for it.
-or if you are using a customized widget a lot, Flutter let you extract it, give it a name and use it again without rewriting the whole code again but by just writing the name you chose for it
In that case you can create your custom scaffold wrapper.
class ScaffoldWrapper extends StatelessWidget {
const ScaffoldWrapper({Key? key, required this.child}) : super(key: key);
final Widget child;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
child: child,
),
),
);
}
}
Now you can replace all occurrence of your mentioned code block with this..
ScaffoldWrapper(child: Container()); // your widget contents

Flutter - prevent rebuild when using MediaQuery

I want to use MediaQuery to build widgets based on screen height and width. The problem, also referenced in #26004, is that I only want to query the size data once, for example in initState. MediaQuery documentation states
Querying the current media using MediaQuery.of will cause your widget to rebuild automatically whenever the MediaQueryData changes (e.g., if the user rotates their device).
, but that causes unnecessary rebuilds in my application. Specifically, it causes rebuild of widgets if there are changes to insets or padding (such as when keyboard is displayed).
Is there an alternative to MediaQuery which wouldn't cause rebuilds when MediaQueryData changes?
I had this issue as well and initially thought that the MediaQuery is causing unnecessary rebuilds, but if you think about it you do want the widgets to rebuild (in cases of device rotation, keyboard popup) for the app to have a responsive design.
You could do something like this:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Builder(builder: (context) {
ResponsiveApp.setMq(context);
return MyHomePage(title: 'Flutter Demo Home Page');
}),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Flex(
direction:
ResponsiveApp().mq.size.width > ResponsiveApp().mq.size.height
? Axis.horizontal
: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ResponsiveApp {
static MediaQueryData _mediaQueryData;
MediaQueryData get mq => _mediaQueryData;
static void setMq(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
}
}
I set the mediaQueryData at the beginning with ResponsiveApp.setMq(context) and I used the Builder because you can only use the MediaQuery one context below the MaterialApp widget. After the _mediaQueryData is set you can get it whenever you want to build widgets based on the screen size.
In this code I just change the Axis direction when the device is rotated and the widget needs to rebuild to show the changed direction.
You could also have something like :
if (_mediaQueryData.size.shortestSide < 400)
//phone layout
else if(_mediaQueryData.size.shortestSide >= 400 && _mediaQueryData.size.shortestSide < 600)
//tablet layout
else
//web layout
and resizing the window in web will cause the widgets to rebuild multiple times and display the desired layout.
But if you don't want to use MediaQuery at all, you can check the Window class from dart:ui.
LayoutBuilder seems preferable over every use of MediaQuery for sizing a viewport (either the whole screen, or the space left in a column or other layout).
LayoutBuilder also works hard to avoid rebuilding its child if the size doesn't change and the parents haven't had to re-layout.
The builder function is called in the following situations:
The first time the widget is laid out.
When the parent widget passes different layout constraints.
When the parent widget updates this widget.
When the dependencies that the builder function subscribes to change.
The builder function is not called during layout if the parent passes
the same constraints repeatedly.
And you don't have to think about "the height of the appbar" ever again, because you're getting the space left, not the total space on the screen.
Check it out: https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html
In my case, the problem was happening because I was controlling the focus manually using:
onEditingComplete: () {
FocusScope.of(context).nextFocus();
}
The context used was the Parent's context, and it was causing the rebuilding. Not sure why it happened, but it stopped once I've wrap the TextFormField with a Builder and started using its context instead.
Note: I'm also using MediaQuery.of(context).size.height normally (without the rebuild side effect) to set the Widget's Parent height 🤔

Flutter Search bar in ActionBar like yelp app

I am trying to build an application location base and I want a search bar like this image shows. That search bar should be able search for locations and text. Does anyone have a pre-built search bar like this?
You can create you own custom app Bar.Simply give appBar property(in Scaffold) an PreferredSize and design as you like. Below is the implementation:
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar:PreferredSize(
preferredSize: Size.fromHeight(45.0),
//give child any Widget you like
child: Center(
child: Container(
width:MediaQuery.of(context).size.width*0.9,
height:100,
child:Center(child: Text("CUSTOM APP BAR")),
color:Colors.blueAccent,
),
),
),
);
}
}

Make Divider match width of shrink-wrapped container?

I want to build a widget containing two Text widgets and one Divider widget, stacked vertically. The Divider should have the same width as the wider of the two Text widgets. The whole combined widget should consume no more layout space than its visible elements; that is, it should be shrink-wrapped.
I would like it to look like the following image:
(I added the light gray background here only to make my desired bounding box more apparent.)
It is unclear to me how to simultaneously force the widget hierarchy to assume the natural maximum width of the text while causing the Divider to stretch to a width only as great as the width of the text. If possible, I would like to do this without writing any custom layout widgets and without directly assigning a width to the Divider using measurements of widgets following the first layout or rendering pass.
Here is some code I tried in DartPad (https://dartpad.dev/flutter), but, naturally, it does not have the desired effect:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Text("Lorem ipsum"),
Text("dolor"),
Divider(thickness: 1.0, color: Colors.red),
]),
)));
}
}
My end goal is to have code that works in Android Studio 3.5.3, Windows 10 64-bit.
How can I fix (or replace) my code to accomplish this?
Use IntrinsicWidth see https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e for detailed options
https://dartpad.dev/79edda902aa584124dafd56c35d612fd
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:
Center(child: IntrinsicWidth(
child:Column(mainAxisSize: MainAxisSize.min , children: <Widget>[
Text("Lorem ipsum"),
Text("dolor"),
Divider(thickness: 1.0, color: Colors.red),
]))),
));
}
}