Is it possible to override Scaffold or MaterialApp? - dart

I'm a beginner in flutter and all my application will use Direction: TextDirection.rtl,
Can i override Scaffold or MaterialApp to return Direction: TextDirection.rtl,
Or how can I make all screens in app Direction: TextDirection.rtl
Thanks in advance
Show my code:
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(),
),
);

First of all, You can't override a class. You can override its methods. Coming to your question, yes you can override MaterialApp and Scaffold classes' methods. However, there are some methods which are "uncommon" to be overridden. You can simply check the documentation for these two classes and get an idea.
MaterialApp Class
Scaffold Class
Also, when you want to override a class (like in your question) if you mean to override the "constructor" of this class, then it is not possible to override a base class constructor in Dart.

Related

How can I copy another buttons style?

I have a TextField widget with the labelText "Description".
I'm trying to make this TextField have the same style as a FlatButton widget
I was reading about using copyWith but I don't fully understand how to use it.
I was also looking at https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/flat_button.dart but I don't really think this explains much
return TextField(
style: TextStyle(),
onChanged: _bloc.changeEventDescription,
decoration: InputDecoration(
labelText: "Description", border: InputBorder.none),
);
Setting border: InputBorder.none at least got rid of the line underneath the FlatButton
The dream is for TextField to look like a default FlatButton
Thanks!!
You can extend FlatButton and create a custom widget (just like FlatButton extends MaterialButton). So your class will look something like this -
class myButton extends FlatButton {}
You can override child to TextFormField.

Flutter root Column widget expanding to whole screen, why?

I'm new to flutter / dart and am just finding my feet.
Been having a play with a really simple test UI. I'm using the Material App and Scaffold widgets and placing a Column widget in the 'body' of the Scaffold widget. It automatically expands to take up the whole screen when I use the inspect widget tool.
This is the code..
class TestWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text('bob'),
],
),
);
}
}
If I then nest a Column widget it doesn't expand to take up the vertical space like its parent did, I can change that and take up the space by using the Expanded widget like this..
class TestWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text('bob'),
Expanded(
child: Column(children: [
Text('bob2'),
]),
),
],
),
);
}
}
I'm just trying to understand why the parent 'root' Column takes up all the space it can by default but when I remove the Expanded widget the nested Column doesn't?
Must be something simple but I'm not seeing it when I look through the docs and understand.
Many thanks for any help.
This is a layout constraint applied to the root widget by Flutter.

How to set app theme data in different pages in flutter?

I have a list view on my homepage where if I clicked on it will move to a new page the first one the theme should be blue, and the next one the theme data should be red.
Like how Chat Customization in Facebook's Messenger works.
You should wrap your Page widget inside a Theme widget. Something like below:
#override
Widget build(BuildContext context) {
return Theme(
data: ThemeData(
backgroundColor: Colors.red,
),
child: Builder(
builder: (context) {
return YourPageWidget(context);
}
),
);
}
There is one thing you should aware of. Using a Builder() to pass the latest context (including your custom theme data in this new context) to the child widget.
If not using Builder, in some cases, YourPageWidget can't get correct theme data with command Theme.of(context)...
For more information, you can reference the document Create unique ThemeData

Spread main Flutter Scaffold (AppBar +TabBar + PopupMenu, Drawer, main Body) over separate, smaller files?

'Allo,
My main file is getting up to 1000 lines of code and I can't help but think I could save time by separating the Scaffold into 3 or 4 .dart files. Is this possible?
Between the AppBar and Drawer I'm already up to 500+ lines of code because of all the links and design parameters. I'd like to extricate this code instead of having to scroll through it continually when I'm working on the main body.
Anytime I've tried to take out the drawer and put it in a separate file I get errors everywhere. Problems with 'dynamic' and 'widgets' and return types, etc.
What can I take out the scaffold and reference it to another file?
child: new Scaffold(
appBar: new AppBar(
bottom: new TabBar(tabs:[.....]),
actions: <Widget> [
new PopupMenuButton<xx>()
],),],), //end appBar
drawer: new Drawer(......), //end drawer
body: TabBarView(....), //end body
), //end scaffold
I wouldn't mind leaving the main body in this main file but I might also take it out if i had more options. Just want to reduce a 1000+ lines into 2-3 chunks, files of manageable space.
Any ideas?
There is most certainly a way to organize this across different files. In addition to being easier to maintain and test, this may also increase performance if state is involved (because if state changes you have to rebuild the entire tree rather than only rebuilding leaf nodes).
However, this also means that if you have state involved and sprinkled about in your one large build() method then you may have some additional considerations as you organize across files. This is assuming you would create new custom widgets to wrap the various components and you would need to orchestrate the state appropriately.
So with the goal of breaking this build method into different sub Widgets, I recommend you start by breaking it up into functions first:
from:
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
bottom: new TabBar(tabs:[.....]),
actions: <Widget> [
new PopupMenuButton<xx>()
],),],), //end appBar
drawer: new Drawer(......), //end drawer
body: TabBarView(....), //end body
);
}
to:
Widget build(BuildContext context) {
return new Scaffold(
appBar: _appBar(),
drawer: _drawer(),
body: _body(),
);
}
Widget _appBar() {
return new AppBar(
bottom: new TabBar(tabs:[.....]),
actions: <Widget> [
new PopupMenuButton<xx>()
],),],);
}
Widget _drawer() {
...
}
Widget _body() {
return TabBarView();
}
At this point, you may start to realize what data/state is being passed around as you will have to add parameters to these new helper methods.
If you have a lot of parameter passing (especially on state that changes), you will have other considerations outside the scope of this answer (and we would need to see what state you are actually dealing with).
The next step is to create a new Widget for each of these methods.
From:
Widget _appBar() {
return new AppBar(
bottom: new TabBar(tabs:[.....]),
actions: <Widget> [
new PopupMenuButton<xx>()
],),],);
}
To:
Widget _appBar(...) {
return MyAppBar(...);
}
class MyAppBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new AppBar(
bottom: new TabBar(tabs:[.....]),
actions: <Widget> [
new PopupMenuButton<xx>()
],),],);
}
}
You can define MyAppBar in it's own file.
You can also bypass the _appBar(...) method and just construct the new widget in the main build() method (assuming you have no other complex setup):
Widget build(BuildContext context) {
return new Scaffold(
appBar: MyAppBar(),
drawer: MyDrawer(),
body: _body(), // you might want to keep the body in the same file
);
}
Easiest way are methods:
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(),
...
);
}
Widget _buildAppBar() {
return AppBar(...);
}
You can also use separate widgets. The widget in the appBar slot must implement PreferredSizeWidget:
class TestPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(),
body: MyBody(),
);
}
}
class MyAppBar extends StatelessWidget implements PreferredSizeWidget {
#override
Size get preferredSize => Size.fromHeight(kToolbarHeight); // whatever height you want
#override
Widget build(BuildContext context) {
return AppBar();
}
}
class MyBody extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text('Hello World'),
),
);
}
}
Of course if place them in a different file, you have to import it:
import 'package:myapp/widgets/some_widget.dart';

Flutter Trying to fire a showModalBottomSheet mystery

I question myself sometimes, whether I'm dumb, or Dart (Flutter) is weird.
How does this not work?
I'm using https://github.com/apptreesoftware/flutter_google_map_view
I show a map, and have added markers.
Since the package supports listeners, when a marker is tapped, I want to show a modal.
Does the listener work? Yep, because the print statement happens.
Does the modal work? I don't know. No error shows, nothing!
mapView.onTouchAnnotation.listen((annotation) {
print(annotation);
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 260.0,
child: Text('Text'),
);
},
);
});
Please, what is the magic bullet?
Edit
Lemme thrown in more flesh. This is my Scaffold widget.
MapView mapView = new MapView();
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
key: scaffoldKey,
appBar: new AppBar(
title: new Text('Map View Example'),
),
body: new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
showMap(context),
],
),
),
);
And showMap(...) looks like this:
showMap(context) {
mapView.show(
new MapOptions(
mapViewType: MapViewType.normal,
showUserLocation: true,
showMyLocationButton: true,
showCompassButton: true,
initialCameraPosition:
new CameraPosition(new Location(5.6404963, -0.2285315), 15.0),
hideToolbar: false,
title: "Dashboard"),
// toolbarActions: [new ToolbarAction("Close", 1)],
);
mapView.onMapReady.listen((_) {
mapView.setMarkers(_markers);
});
mapView.onTouchAnnotation.listen((annotation) {
print(annotation);
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
height: 260.0,
child: Text('Text'),
);
},
);
});
}
The reason you've having issues is that your context doesn't contain a scaffold. If you look what you're doing in your code, your context actually comes from the widget enclosing your scaffold.
YourWidget <------------ context
MaterialApp
Scaffold
AppBar
Column
showMap....
There are a couple of ways to get around this. You can use a Builder widget something like this:
body: new WidgetBuilder(
builder: (context) => new Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
showMap(context),
],
)
),
in which case the context is actually rooted below the scaffold.
YourWidget
MaterialApp
Scaffold
AppBar
Builder <------------ context
Column
showMap....
However, what I would actually recommend is breaking your class into multiple classes. If your build function gets large enough you have to separate it out into another function (that's only used once), there's a good chance you need a new widget!
You could either make a body widget (probably Stateless), or a widget just for showing the map (Stateless or Stateful depending on your needs)... or more likely both!
Now as to why you're not seeing any errors... are you running in debug or release mode (if you're in debug mode there should be a little banner in the top right of the screen)? If you're in release mode it might ignore the fact that there is no scaffold in the context and fail silently, whereas in debug mode it should throw an assertion error. Running from the IDE or with flutter run generally runs in debug mode, but you may have changed it.

Resources