AppBar Title sticks to the left side of the screen - dart

Why does the Title stick to the left instead of leaving some space ?
This is the Scaffold code
return new Scaffold(
appBar: new AppBar(title: const Text('Friendlychat')),);

This is a regression in current flutter alpha release which is fixed in master - see this issue
For now, any of the workarounds mentioned in the answer by aziza can be used, but you will have to revert it when the new alpha is released

There are few ways you can modify that:
You can wrap your title widget inside a Padding widget and use the padding property to indent the area on the left.
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Padding (child: new Text ("Friendly Chat"),
padding:const EdgeInsets.only(left: 20.0) ),
),
);
}
Or you can add an empty Container in the leading property of your AppBar.
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title:new Text ("Friendly Chat"),
leading: new Container(),
),
);
}
If you want the title to be centered, set the property centerTitle in your AppBar to true
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title:new Text ("Friendly Chat"),
centerTitle: true,
),
);
}

This is a regression in current flutter alpha release which is fixed in master as pointed out by #aptik.Thanks

Related

How to change shadow color of AppBar?

I am trying to change shadow elevation color of the AppBar but can't find any property for that.
I went to the original implementation as well but cant find any property to change shadow color.
AppBar(
title: Image.asset(
"images/toolbar_logo.webp",
width: 80,
height: 50,
),
centerTitle: true,
backgroundColor: white,
),
I cant wrap the AppBar inside a Material Widget.
I know i can avoid the app bar property and create a custom class and add it to my body of Scaffold,
but is it possible to change using shadow color of AppBar?
There isn't a way to change the colour of the default shadow but you can get around it by wrapping your AppBar in a Container which is inside a PreferredSize widget:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: PreferredSize(
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.red,
offset: Offset(0, 2.0),
blurRadius: 4.0,
)
]),
child: AppBar(
elevation: 0.0,
title: Text("Test"),
),
),
preferredSize: Size.fromHeight(kToolbarHeight),
),
body: Container(),
),
);
}
}
The accepted answer is a bit expired. You can do this in two ways:
Changing directly through the AppBar property:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(shadowColor: Colors.green),
body: Container(),
),
);
}
}
Or by using the Theme:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
appBarTheme: AppBarTheme(
shadowColor: Colors.white,
),
),
home: Scaffold(
appBar: AppBar(),
body: Container(),
),
);
}
}
You can use the shadowColor property of Appbar to color to paint the shadow below the app bar.

How to prevent Flutter app from scrolling to top after calling setState?

I have an ExpansionPanelList inside a SingleChildScrollView. Whenever I (un)fold a panel and therefore call setState, the SingleChildScrollView scrolls back to the top. How can I prevent this?
#override
Widget build(BuildContext context) {
final _scaffoldKey = new GlobalKey<ScaffoldState>();
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: new Text(widget.title),
),
body: new SingleChildScrollView(
child: new ExpansionPanelList(
children: <ExpansionPanel>[
// panels
],
expansionCallback: (int index, bool isExpanded) {
setState(() {
// toggle expanded
});
},
), // ExpansionPanelList
), // SingleChildScrollView
); // Scaffold
}
This answer suggests using a custom ScrollController with keepScrollOffset set to true, however this is the default value and setting it explicitly to true therefore does not change anything.
That's because you are using a new Key every time you rebuild the widget (setState).
To fix your issue just move the code below outside the build method
final _scaffoldKey = new GlobalKey<ScaffoldState>();
Like this :
final _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: new Text(widget.title),
),
I was having the same problem, and somehow the answer from #diegoveloper did not do the trick for me.
What i ended up doing was separating the SingleChildScrollView in an independent StatefulWidget: That also fixed the scroll animation.
My code then ended up being something like
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: MyExpansionList(),
...
class MyExpansionListextends StatefulWidget {
#override
_MyExpansionListState createState() => _MyExpansionListState();
}
class _MyExpansionListState extends State<MyExpansionList> {
#override
Widget build(BuildContext context) {
return Scrollbar(
isAlwaysShown: true,
showTrackOnHover: true,
child: SingleChildScrollView(
child: Column(
children: [
ExpansionPanelList(animationDuration: Duration(seconds: 1),
In this way the setState() did update only the ExpansionPanelList/ScrollView and not the whole Scaffold.
I hope this also helps others facing same problem...
Nothing helped me until I realised that in the build() function I was calling jumpTo() of the controller that was attached to my list. Like this:
#override
Widget build(BuildContext context) {
if (widget.controller.hasClients) {
widget.controller.jumpTo(0);
}
...
}
I removed these lines and the problem was gone. Happy coding :)
You have to pass a key to the SingleChildScrollView. Otherwise, its state is renewed every setState call.
final _scrollKey = GlobalKey();
SingleChildScrollView(
key: _scrollKey,
child:

Dynamic AppBar of Flutter

I have to change AppBar appearance and items dynamically (by tapping on another UI elements).
What is the best approach?
I tested several methods. For example,
return Scaffold(
appBar: StreamBuilder(
stream: bloc.tasks,
builder: (context, AsyncSnapshot<List<UserTask>> tasks) {
return new AppBar();/// my setup is here
}),
but this is obviously doesn't compile.
appBar requires a widget that implements PreferredSizeWidget, and StreamBuilder isn't one.
You can wrap that tree into a PreferredSize:
Scaffold(
appBar: PreferredSize(
preferredSize: const Size(double.infinity, kToolbarHeight),
child: // StreamBuilder
),
)

SafeArea not working in persistent bottomsheet in Flutter

I am using MaterialApp and Scaffold + SafeArea for screens. All works well until I try to use persistent BottomSheet. BottomSheet content igores SafeArea and are shown below system controls, for example in iPhone X.
I tried to wrap BottomSheet contents in another SafeArea element, but it did not help.
Is there a way to get the same functionality as SafeArea to work in BottomSheet? If yes then how?
Just make the root Widget of the showModalBottomSheet be a SafeArea Widget
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[...
I have faced this issue too. When I changed code from showModalBottomSheet to _scaffoldKey.currentState.showBottomSheet my SafeArea stopped working.
You can solve it with these steps:
create key for your Scaffold GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
assign created key to your Scaffold key: _scaffoldKey,
set bottom padding to your bottom sheet
padding: EdgeInsets.only(bottom: MediaQuery.of(_scaffoldKey.currentState.context).viewPadding.bottom)
Here is a result, I also added 15 padding to top, left and right.
I solved the problem by adding container and padding inside with: MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top
Container(
padding: EdgeInsets.only(
top: MediaQueryData.fromWindow(WidgetsBinding.instance.window).padding.top),
child: MyOriginalWidgetForBottomSheet(),
)
Don't get from the context (like MediaQuery.of(context).padding.top) as the padding always returns 0
In my case the top safe area was the problem and a practical workaround was to set padding to the height of the app bar with AppBar().preferredSize.height
Padding(
padding: EdgeInsets.fromLTRB(0,AppBar().preferredSize.height,0,0),
child: Text(
'Your Order',
style: headingMediumBlack,
),
),
I tried out this simple code and it works as intended in the iOS Simulator with an iPhone X:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SafeArea(
child: new Scaffold(
appBar: new AppBar(
title: new Text('SafeArea demo'),
),
body: new Center(
child: new TapMe(),
),
),
));
}
}
class TapMe extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new RaisedButton(
child: new Text('Tap Me'),
onPressed: () => Scaffold
.of(context)
.showBottomSheet((context) => new Text('I\'ve been tapped')),
);
}
}
What version of Flutter are you using?
Faced this issue too with top-notch.
Resolved using dart:ui.window.viewPadding.top / ui.window.devicePixelRatio
How it works:
The dart:ui.window.viewPadding is the number of physical pixels on each side of the display rectangle into which the view can render.
By dividing to ui.window.devicePixelRatio we should receive logic pixels.
So in summary code is
showModalBottomSheet<bool>(
context: context,
builder: (BuildContext context) => Container(
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.only(
top: ui.window.viewPadding.top / ui.window.devicePixelRatio,
),
),
);
IMHO, The cleanest workaround is to set InitialChildSize to 0.9
DraggableScrollableSheet(
initialChildSize: 0.9,
minChildSize: 0.2,
maxChildSize: 0.9,
expand: false,
builder: (BuildContext context, ScrollController scrollController) {
}
)
This has been fixed -- just set useSafeArea: true in showModalBottomSheet. https://github.com/flutter/flutter/issues/39205

Paint an Gradient on screen

To implement a color picker, I want to draw a rectangle with a gradient of colors inside. I tried to use a container with a DecoratedBox but it didn't quite work, as I had to give it a width, and I wanted it to fill its parent.
What is the best way to draw a Gradient in flutter?
It sounds like you already know how to draw a gradient and your question is more about how to make a DecoratedBox as big as possible.
If your DecoratedBox appears in a Column or Row, consider wrapping it in an Expanded and setting the crossAxisAlignment to CrossAxisAlignment.stretch.
If your DecoratedBox is a child of a widget that doesn't provide a size to its child (e.g. Center), try wrapping it in a ConstrainedBox with a constraints of new BoxConstraints.expand(). Here's an example:
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Gradient Example',
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Gradient Example'),
),
body: new Center(
child: new ConstrainedBox(
constraints: new BoxConstraints.expand(),
child: new DecoratedBox(
decoration: new BoxDecoration(
gradient: new LinearGradient(
colors: <Color>[Colors.red, Colors.blue]
),
),
),
),
),
);
}
}

Resources