Flutter: Setting the height of the AppBar - dart

How can I simply set the height of the AppBar in Flutter?
The title of the bar should be staying centered vertically (in that AppBar).

You can use PreferredSize:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Example',
home: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50.0), // here the desired height
child: AppBar(
// ...
)
),
body: // ...
)
);
}
}

Use toolbarHeight:
There's no longer a need to use PreferredSize. Use toolbarHeight with flexibleSpace.
AppBar(
toolbarHeight: 120, // Set this height
flexibleSpace: Container(
color: Colors.orange,
child: Column(
children: [
Text('1'),
Text('2'),
Text('3'),
Text('4'),
],
),
),
)

You can use PreferredSize and flexibleSpace for it:
appBar: PreferredSize(
preferredSize: Size.fromHeight(100.0),
child: AppBar(
automaticallyImplyLeading: false, // hides leading widget
flexibleSpace: SomeWidget(),
)
),
This way you can keep the elevation of AppBar for keeping its shadow visible and have custom height, which is what I was just looking for. You do have to set the spacing in SomeWidget, though.

The easiest way is to use toolbarHeight property in your AppBar
Example :
AppBar(
title: Text('Flutter is great'),
toolbarHeight: 100,
),
You can add flexibleSpace property in your appBar for more flexibility
Output:
For more controls , Use the PreferedSize widget to create your own appBar
Example :
appBar: PreferredSize(
preferredSize: Size(100, 80), //width and height
// The size the AppBar would prefer if there were no other constraints.
child: SafeArea(
child: Container(
height: 100,
color: Colors.red,
child: Center(child: Text('Fluter is great')),
),
),
),
Don't forget to use a SafeArea widget if you don't have a safeArea
Output :

At the time of writing this, I was not aware of PreferredSize. Cinn's answer is better to achieve this.
You can create your own custom widget with a custom height:
import "package:flutter/material.dart";
class Page extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Column(children : <Widget>[new CustomAppBar("Custom App Bar"), new Container()],);
}
}
class CustomAppBar extends StatelessWidget {
final String title;
final double barHeight = 50.0; // change this for different heights
CustomAppBar(this.title);
#override
Widget build(BuildContext context) {
final double statusbarHeight = MediaQuery
.of(context)
.padding
.top;
return new Container(
padding: new EdgeInsets.only(top: statusbarHeight),
height: statusbarHeight + barHeight,
child: new Center(
child: new Text(
title,
style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
);
}
}

In addition to #Cinn's answer, you can define a class like this
class MyAppBar extends AppBar with PreferredSizeWidget {
#override
get preferredSize => Size.fromHeight(50);
MyAppBar({Key key, Widget title}) : super(
key: key,
title: title,
// maybe other AppBar properties
);
}
or this way
class MyAppBar extends PreferredSize {
MyAppBar({Key key, Widget title}) : super(
key: key,
preferredSize: Size.fromHeight(50),
child: AppBar(
title: title,
// maybe other AppBar properties
),
);
}
and then use it instead of standard one

You can simply use toolbarHeight, as follows:
appBar: AppBar(
toolbarHeight: 70.0, // add this line
centerTitle: true, // add this line
title: Text('your title'),
),
but if you have any actions the code above doesn't work as you want
you can use this code
AppBar(
centerTitle: true,
title: Padding(
padding: const EdgeInsets.all(16.0),
child: Stack(
alignment: Alignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Chats', style: TextStyle(color:Colors.black),),
Icon(Icons.add, color: Colors.black,),
],
),
Align(
alignment: Alignment.centerRight,
child: Icon(Icons.add, color: Colors.black,),
),
],
),
),
)

Cinn's answer is great, but there's one thing wrong with it.
The PreferredSize widget will start immediately at the top of the screen, without accounting for the status bar, so some of its height will be shadowed by the status bar's height. This also accounts for the side notches.
The solution: Wrap the preferredSize's child with a SafeArea
appBar: PreferredSize(
//Here is the preferred height.
preferredSize: Size.fromHeight(50.0),
child: SafeArea(
child: AppBar(
flexibleSpace: ...
),
),
),
If you don't wanna use the flexibleSpace property, then there's no need for all that, because the other properties of the AppBar will account for the status bar automatically.

simply use toolbar height ...
AppBar(
title: Text("NASHIR'S APP"),
toolbarHeight: 100,
),

You can use the toolbarHeight property of Appbar, it does exactly what you want.

class AppBarWidget extends StatelessWidget with PreferredSizeWidget {
final String title;
const AppBarWidget({Key? key, required this.title}) : super(key: key);
#override`enter code here`
Widget build(BuildContext context) {
return AppBar(
title: Text(title),
centerTitle: true,
elevation: 0,
actions: [
Padding(
padding: const EdgeInsets.only(right: 10),
child: IconButton(
icon: const FaIcon(FontAwesomeIcons.language),
onPressed: () {},
),
),
],
);
}
#override
Size get preferredSize => const Size.fromHeight(40);// change
}

You can use PreferredSize, by this use can set multiple children widget inside their
appBar: PreferredSize(
preferredSize: Size(MediaQuery.of(context).size.width, 75),
child: Column(children: [
AppBar(
centerTitle: true,
toolbarHeight: 74,
backgroundColor: Colors.white,
elevation: 0,
title: Column(
children: [
Text(
viewModel.headingText,
style: sfDisplay16500Text,
),
SizedBox(
height: 8.0,
),
Text(
viewModel.url.toString(),
style: sfDisplay10400LightBlackText,
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
],
),
),
]),
),
or just directly use toolbarHeight property for only increase hight of appBar.
appBar: AppBar(
title: Text('AppBar Texr'),
toolbarHeight: 200.0, // double
),

Extend AppBar class and override preferredSize
class AppBarCustom extends AppBar {
#override
Size get preferredSize => Size.fromHeight(100);
}
then use it as you would use AppBar class
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBarCustom(),
body:
),
);
}
}

This is simplest and easiest way to change appbar height without changing original theme.
class AppBarSectionView extends StatefulWidget implements PreferredSizeWidget {
const AppBarSectionView({Key? key}) : super(key: key);
#override
_AppBarSectionViewState createState() => _AppBarSectionViewState();
#override
Size get preferredSize => const Size.fromHeight(kToolbarHeight + 20);
}
class _AppBarSectionViewState extends State<AppBarSectionView> {
#override
Widget build(BuildContext context) {
return AppBar(
toolbarHeight: widget.preferredSize.height ,
backgroundColor: Colors.red,
leading: const Icon(Icons.arrow_back_ios_rounded),
title: const Text("This Is Title"),
);
}
}

If you are in Visual Code, Ctrl + Click on AppBar function.
Widget demoPage() {
AppBar appBar = AppBar(
title: Text('Demo'),
);
return Scaffold(
appBar: appBar,
body: /*
page body
*/,
);
}
And edit this piece.
app_bar.dart will open and you can find
preferredSize = new Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
Difference of height!

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.

Flutter positioning widgets in Column

I am trying to set an image in the center of Column, and the Text at the bottom of the image, by wrapping Image and Text in the Column widget and placing it in the Center widget.
Unfortunately, it centers the Column and makes Image to be above the center of the screen.
How can I solve it?
My current code:
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Theme.of(context).primaryColor),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(ImagePaths.newLogoLogin),
Text(Strings.beALocal)
],
),
),
);
}
This can be achieved using the Expanded widget:
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Theme.of(context).primaryColor),
child: Column(
children: [
Spacer(),
Image.asset(ImagePaths.newLogoLogin),
Expanded(
Column(
children: [ Text(Strings.beALocal) ],
mainAxisAlignment: MainAxisAlignment.start
)
)
],
),
);
}
You could use a Stack with a Positioned Text widget inside it.
Full example:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("Test")),
body: Stack(children: [Placeholder(), Test()]),
),
);
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
overflow: Overflow.visible,
children: <Widget>[
Container(
width: 150,
height: 150,
color: Colors.blue,
),
Positioned(child: Text("Some text"), bottom: -25),
],
),
);
}
}
you can use widget SafaArea or calc size of the appbar and the navigation bar, when you have this result use this for remove in height size of screen after this you can add column MainAxisAlignment.center, CrossAxisAlignment.center and add other widget in Column

Make AppBar transparent and show background image which is set to whole screen

I have added AppBar in my flutter application. My screen already have a background image, where i don't want to set appBar color or don't want set separate background image to appBar.
I want show same screen background image to appBar also.
I already tried by setting appBar color as transparent but it shows color like gray.
Example code:
appBar: new AppBar(
centerTitle: true,
// backgroundColor: Color(0xFF0077ED),
elevation: 0.0,
title: new Text(
"DASHBOARD",
style: const TextStyle(
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
fontFamily: "Roboto",
fontStyle: FontStyle.normal,
fontSize: 19.0
)),
)
This is supported by Scaffold now (in stable - v1.12.13+hotfix.5).
Set Scaffold extendBodyBehindAppBar to true,
Set AppBar elevation to 0 to get rid of shadow,
Set AppBar backgroundColor transparency as needed.
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Colors.red,
appBar: AppBar(
// backgroundColor: Colors.transparent,
backgroundColor: Color(0x44000000),
elevation: 0,
title: Text("Title"),
),
body: Center(child: Text("Content")),
);
}
you can use Stack widget to do so. Follow below example.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Home(),
);
}
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Scaffold(
backgroundColor: Colors.transparent,
appBar: new AppBar(
title: new Text(
"Hello World",
style: TextStyle(color: Colors.amber),
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: new Container(
color: Colors.red,
),
),
],
),
);
}
}
You can use Scaffold's property "extendBodyBehindAppBar: true"
Don't forget to wrap child with SafeArea
#Override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
extendBodyBehindAppBar: true,
body: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/background/home.png'),
fit: BoxFit.cover,
),
),
child: SafeArea(
child: Center(
child: Container(
width: 300,
height: 300,
decoration: BoxDecoration(
color: Colors.green,
),
child: Center(child: Text('Test')),
),
)),
),
);
}
None of these seem to work for me, mine went something like this:
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
iconTheme: IconThemeData(color: Colors.white),
elevation: 0.0,
),
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://images.unsplash.com/photo-1517030330234-94c4fb948ebc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1275&q=80'),
fit: BoxFit.cover,
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 100, 0, 0),
child:
// Column of widgets here...
),
),
],
),
);
Output:
A lot of answers but nobody explains why extendBodyBehindAppBar works?
It works because when we assigned extendBodyBehindAppBar as true, then the body of the widget takes the height of AppBar, and we see an image covering the AppBar area.
Simple Example:
Size size = MediaQuery.of(context).size;
return Scaffold(
extendBodyBehindAppBar: true,
body: Container(
// height: size.height * 0.3,
child: Image.asset(
'shopping_assets/images/Fruits/pineapple.png',
fit: BoxFit.cover,
height: size.height * 0.4,
width: size.width,
),
),
);
There could be many cases, for example, do you want to keep the AppBar or not, whether or not you want to make the status bar visible, for that, you can wrap Scaffold.body in SafeArea and if you want AppBar to not have any shadow (unlike the red I provided in example 2), you can set its color to Colors.transparent:
Full image (without AppBar)
Scaffold(
extendBodyBehindAppBar: true,
body: SizedBox.expand(
child: Image.network(
'https://wallpaperaccess.com/full/3770388.jpg',
fit: BoxFit.cover,
),
),
)
Full image (with AppBar)
Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
shadowColor: Colors.red,
title: Text('MyApp'),
),
body: SizedBox.expand(
child: Image.network(
'https://wallpaperaccess.com/full/3770388.jpg',
fit: BoxFit.cover,
),
),
)
that's what I did and it's working
This is supported by Scaffold now (in stable - v1.12.13+hotfix.5).
Set Scaffold extendBodyBehindAppBar to true,
Set AppBar elevation to 0 to get rid of shadow,
Set AppBar backgroundColor transparency as needed.
Best regards
Scaffold(extendBodyBehindAppBar: true);
In my case I did it as follows:
Additional create an app bar with a custom back button (in this case with a FloatingActionButton). You can still add widgets inside the Stack.
class Home extends StatefulWidget {
#override
_EditProfilePageState createState() => _EditProfilePageState();
}
class _HomeState extends State< Home > {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
this._backgroundImage(), // --> Background Image
Positioned( // --> App Bar
child: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
leading: Padding( // --> Custom Back Button
padding: const EdgeInsets.all(8.0),
child: FloatingActionButton(
backgroundColor: Colors.white,
mini: true,
onPressed: this._onBackPressed,
child: Icon(Icons.arrow_back, color: Colors.black),
),
),
),
),
// ------ Other Widgets ------
],
),
);
}
Widget _backgroundImage() {
return Container(
height: 272.0,
width: MediaQuery.of(context).size.width,
child: FadeInImage(
fit: BoxFit.cover,
image: NetworkImage(
'https://images.unsplash.com/photo-1527555197883-98e27ca0c1ea?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80'),
placeholder: AssetImage('assetName'),
),
);
}
void _onBackPressed() {
Navigator.of(context).pop();
}
}
In the following link you can find more information Link
You can Try this This code work for me
#override
Widget build(BuildContext context) {
_buildContext = context;
sw = MediaQuery.of(context).size.width;
sh = MediaQuery.of(context).size.height;
return new Container(
child: new Stack(
children: <Widget>[
new Container(
child: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.all(20.0),
decoration: BoxDecoration(image: backgroundImage),
),
],
),
),
new Scaffold(
backgroundColor: Colors.transparent,
appBar: new AppBar(
title: new Text(Strings.page_register),
backgroundColor: Colors.transparent,
elevation: 0.0,
centerTitle: true,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(20.0),
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: new Form(
key: _formKey,
autovalidate: _autoValidate,
child: FormUI(),
),
),
)
],
),
);
}
backgroundImage
DecorationImage backgroundImage = new DecorationImage(
image: new ExactAssetImage('assets/images/welcome_background.png'),
fit: BoxFit.cover,
);
use stack
set background image
Another Scaffold()
set background color transperant
set custom appbar
use column with singleChildScrollView or ListView
#override Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
backgroundBGContainer(),
Scaffold(
backgroundColor: Colors.transparent,
appBar: appBarWidgetCustomTitle(context: context, titleParam: ""),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
_spaceWdgt(),
Center(
child: Stack(
children: <Widget>[
new Image.asset(
"assets/images/user_icon.png",
width: 117,
height: 97,
),
],
),
),
Widget backgroundBGContainer() {
return Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/images/ground_bg_image.png"),
fit: BoxFit.cover,
),
color: MyColor().groundBackColor),
);
}
don't forget to set foregroundColor attribite to the desired color in order to make the navigation icon and the title visible
Note that the foregroundColor default value is white.

Flutter: Change text when FlexibleSpaceBar is collapsed

I have looked through the Flutter documentation to try and find an event, callback or even a state that I could hook into when the FlexibleSpaceBar is collapsed or expanded.
return new FlexibleSpaceBar(
title: new Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
new Text(_name, style: textTheme.headline),
new Text(_caption, style: textTheme.caption)
]),
centerTitle: false,
background: getImage());`
When the FlexibleSpaceBar is snapped in (collapsed), I want to hide the _caption text and only display the _name text. When it is expanded fully, I obviously want to display both _name & _caption.
How do I go about doing that?
Im new to flutter, so I am somewhat lost on this.
Also reported at https://github.com/flutter/flutter/issues/18567
It's not hard to create your own FlexibleSpaceBar.
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController controller = ScrollController();
#override
Widget build(BuildContext context) {
return CustomScrollView(
physics: ClampingScrollPhysics(),
controller: controller,
slivers: [
SliverAppBar(
expandedHeight: 220.0,
floating: true,
pinned: true,
elevation: 50,
backgroundColor: Colors.pink,
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: () {},
),
flexibleSpace: _MyAppSpace(),
),
SliverList(
delegate: SliverChildListDelegate(
List.generate(
200,
(index) => Card(
child: Padding(
padding: EdgeInsets.all(10),
child: Text('text $index'),
),
),
),
),
)
],
);
}
}
class _MyAppSpace extends StatelessWidget {
const _MyAppSpace({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, c) {
final settings = context
.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>();
final deltaExtent = settings.maxExtent - settings.minExtent;
final t =
(1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent)
.clamp(0.0, 1.0) as double;
final fadeStart = math.max(0.0, 1.0 - kToolbarHeight / deltaExtent);
const fadeEnd = 1.0;
final opacity = 1.0 - Interval(fadeStart, fadeEnd).transform(t);
return Stack(
children: [
Center(
child: Opacity(
opacity: 1 - opacity,
child: getTitle(
'Collapsed Title',
)),
),
Opacity(
opacity: opacity,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
getImage(),
getTitle(
'Expended Title',
)
],
),
),
],
);
},
);
}
Widget getImage() {
return Container(
width: double.infinity,
child: Image.network(
'https://source.unsplash.com/daily?code',
fit: BoxFit.cover,
),
);
}
Widget getTitle(String text) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 26.0,
fontWeight: FontWeight.bold,
),
),
);
}
}
You can use AnimatedOpacity class.
flexibleSpace: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
var top = constraints.biggest.height;
return FlexibleSpaceBar(
title: AnimatedOpacity(
duration: Duration(milliseconds: 300),
//opacity: top > 71 && top < 91 ? 1.0 : 0.0,
child: Text(
top > 71 && top < 91 ? "Collapse" : "Expanded",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
)),
background: Image.network(
"https://images.ctfassets.net/pjshm78m9jt4/383122_header/d79a41045d07d114941f7641c83eea6d/importedImage383122_header",
fit: BoxFit.cover,
));
}),
Can check original answer from this link
https://stackoverflow.com/a/53380630/9719695
It can be done like this :
inside your initState method add the scroll listener like that :
ScrollController _controller;
bool silverCollapsed = false;
String myTitle = "default title";
#override
void initState() {
super.initState();
_controller = ScrollController();
_controller.addListener(() {
if (_controller.offset > 220 && !_controller.position.outOfRange) {
if(!silverCollapsed){
// do what ever you want when silver is collapsing !
myTitle = "silver collapsed !";
silverCollapsed = true;
setState(() {});
}
}
if (_controller.offset <= 220 && !_controller.position.outOfRange) {
if(silverCollapsed){
// do what ever you want when silver is expanding !
myTitle = "silver expanded !";
silverCollapsed = false;
setState(() {});
}
}
});
}
then wrap your silverAppBar inside CustomScrollView and add the controller to this CustomScrollView like that :
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: CustomScrollView(
controller: _controller,
slivers: <Widget>[
SliverAppBar(
expandedHeight: 300,
title: myTitle,
flexibleSpace: FlexibleSpaceBar(),
),
SliverList(
delegate: SliverChildListDelegate(<Widget>[
// your widgets inside here !
]),
),
],
),
);
}
finally change the condition value _controller.offset > 220 to fit your need !
FlexibleSpaceBar per se won't be enough. You need to wrap it into CustomScrollView and SliverAppBar. These widgets must be controller by a ScrollController, which will fire an event whenever scroll offset changes. Based on it, you can find out if app bar is collapsed or expanded, and change the content accordingly. Here you will find a working example.
Give an height in padding in FlexibleSpaceBar
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.only(
top: 100, // give the value
title: Text(
"Test"
),
Follow up to Vishnu Suresh answer:
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.only(
top: kToolbarHeight, // give the value
title: Text(
"Test"
),
This will use the appbar height for the padding.

Prevent scrolled Hero from jumping on top of the app bar

I have a Hero that can be scrolled so that part of it is offscreen. When I trigger a transition, it appears to abruptly jump on top of the AppBar and then jumps back under it when the transition is reversed. How do I force the AppBar to stay on top of the Hero?
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new Example(),
theme: new ThemeData(primaryColor: Colors.orange),
debugShowCheckedModeBanner: false,
));
}
Widget positionHeroOverlay(BuildContext context, Widget overlay, Rect rect, Size size) {
final RelativeRect offsets = new RelativeRect.fromSize(rect, size);
return new Positioned(
top: offsets.top,
right: offsets.right,
bottom: offsets.bottom,
left: offsets.left,
child: overlay,
);
}
class LogoPageRoute extends MaterialPageRoute<Null> {
LogoPageRoute(this.colors) : super(
builder: (BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter Logo'),
),
body: new ConstrainedBox(
constraints: new BoxConstraints.expand(),
child: new Hero(
tag: colors,
child: new FlutterLogo(colors: colors),
),
),
);
},
);
/// The color of logo to display
final MaterialColor colors;
#override
final Duration transitionDuration = const Duration(seconds: 1);
}
final List<MaterialColor> swatches = [
Colors.blue,
Colors.orange,
Colors.green,
];
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('All Logos'),
),
body: new ListView(
children: swatches.map((MaterialColor colors) {
return new InkWell(
onTap: () {
Navigator.push(context, new LogoPageRoute(colors));
},
child: new Hero(
tag: colors,
child: new FlutterLogo(size: 360.0, colors: colors),
),
);
}).toList(),
),
);
}
}
Wrap your AppBar in a Hero to force it to stay on top.
appBar: new PreferredSize(
child: new Hero(
tag: AppBar,
child: new AppBar(
title: new Text('All Logos'),
),
),
preferredSize: new AppBar().preferredSize,
),
For the AppBar of the detail page, I would recommend forcing the back button to be displayed so that it appears at the same time that the page title changes.
appBar: new PreferredSize(
child: new Hero(
tag: AppBar,
child: new AppBar(
leading: const BackButton(),
title: new Text('Flutter Logo'),
),
),
preferredSize: new AppBar().preferredSize,
),
Here's what it looks like:
i've fixed it here https://github.com/zombie6888/scrolled_hero by providing bottom and top offset to hero animation builder

Resources