Why is the Scaffold content in my Flutter app not going under my custom AppBar? - flutter

When I use a regular AppBar in a Scaffold, all of the content is pushed down so it's not covered. However, now that I created a custom FloatingAppBar, the content goes under the app bar even though I'm using it the same way. Also, since the FloatingAppBar has to implement PreferredSizeWidget, I also have to give it a preferred size from the height which makes the height of the app bar very small when I use it in a bottom modal widget. Is there any way to get around that? Here is a screenshot of the issue and the code for the custom app bar:
import 'package:flutter/material.dart';
class FloatingAppBar extends StatelessWidget implements PreferredSizeWidget {
const FloatingAppBar(
{Key? key,
required this.title,
required this.leading,
required this.actions})
: super(key: key);
final Widget leading;
final Widget title;
final List<Widget> actions;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(40),
child: ClipRRect(
borderRadius: BorderRadius.circular(40),
child: Container(
color: const Color(0xFFd3d8e9),
height: 120,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
leading,
title,
Row(
children: actions,
)
],
),
),
),
),
),
);
}
#override
Size get preferredSize => const Size.fromHeight(120);
}

The reason of this issue is that you set the appbar height 120, but the actual height you give to appbar is 120 + padding top + padding bottom. in order to fix it , you could do this:
Size get preferredSize => const Size.fromHeight(120 + 40 + 40);
For your color issue, because you know the app bar height 120 in this case, you can add top padding to your scaffold body to fix the background color issue.

Related

Setting a Window Drag Point in Flutter

My Flutter application makes use of the relatively new Windows build tools and the community fluent_ui package.
In an attempt to make my application look more native, I have opted to remove the default Windows title bar using the window_manager package and implement my own. However, this introduces the issue of not being able to move the window by dragging the top of it.
Is there a way to make a widget a window drag point to allow for this?
I recently found a solution by making DraggableAppBar. I'm also using window_manager package to add window control buttons to appbar.
Solution: use DraggableAppBar instead of AppBar in scaffold.
import 'package:flutter/material.dart';
import 'package:universal_platform/universal_platform.dart';
import 'package:window_manager/window_manager.dart';
class DraggebleAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
final Brightness brightness;
final Color backgroundColor;
const DraggebleAppBar({
super.key,
required this.title,
required this.brightness,
required this.backgroundColor,
});
#override
Widget build(BuildContext context) {
return Stack(
children: [
getAppBarTitle(title),
Align(
alignment: AlignmentDirectional.centerEnd,
child: SizedBox(
height: kToolbarHeight,
width: 200,
child: WindowCaption(
backgroundColor: backgroundColor,
brightness: brightness,
),
),
)
],
);
}
Widget getAppBarTitle(String title) {
if (UniversalPlatform.isWeb) {
return Align(
alignment: AlignmentDirectional.center,
child: Text(title),
);
} else {
return DragToMoveArea(
child: SizedBox(
height: kToolbarHeight,
child: Align(
alignment: AlignmentDirectional.center,
child: Text(title),
),
),
);
}
}
#override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

How to fix a widget to the right side of a ListView on Flutter Web

I have a Flutter Web application where I need to show a widget on the right side of a ListView when I click an item and this widget should always be visible on screen. I can achieve my objective puting both on a Row and using a scrollable only for the ListView, but that requires the ListView to be wrapped by a widget with defined height.
Defining a container with height to wrap the ListView breaks the responsiveness when I resize the browser, as the container doesn't fit the height of the screen.
I thought of using the shrinkWrap property of the ListView so I don't have to wrap it in a widget with predefined height, but that makes the whole Row scrollable vertically, eventually causing the widget to leave the viewport.
I would appreciate if somebody knows how could I keep this right side widget fixed on screen so I can achieve my objective without losing responsiveness.
Here's something similitar to what I've got so far:
class PageLayout extends StatefulWidget {
const PageLayout({Key? key, required this.items}) : super(key: key);
final List<String> items;
#override
State<PageLayout> createState() => _PageLayoutState();
}
class _PageLayoutState extends State<PageLayout> {
final rightSideWidget = Container(
decoration: BoxDecoration(
color: Colors.red,
border: Border.all(color: Colors.white, width: 2),
),
height: 200);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.49,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) => Container(
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(color: Colors.white, width: 2),
),
height: 200,
child: Center(
child: Text(
widget.items[index],
style: const TextStyle(color: Colors.white),
),
),
),
itemCount: widget.items.length,
),
),
Expanded(child: rightSideWidget),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
I want rightSideWidget to be always centered on screen or follow the scroll.
You can divide your screen into two sections, right section and left section; thereby being able to control behaviour of widgets in both sections.
Divide the overall screen into 2 proportional sections using a Row
widget
Put this Row widget inside a Container with height equal to screen height for preserving responsiveness | Use MediaQuery to get current height of page
Now left hand section can individually scroll, and on click of any option from this section you can define behaviour for right section; while keeping the left section constant throughout page lifecycle

flutter image placeholder (FadeInImage) without setting fixed size?

How can I use something like FadeInImage to setup and hold the layout of a page before images have downloaded? As expected, just using Image.network causes the page to jump around once the images load and become visible. I don't have set image sizes (i allow them to resize based on screen/etc) and want to avoid setting a fixed height. The images load and show fine using FadeInImage however the screen still jumps a lot.
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: AppBar(
title: Text('Welcome!'),
),
drawer: sideDrawer(),
body: new SingleChildScrollView(
padding: const EdgeInsets.all(8.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(height: 28),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(width: 64),
Flexible( // tried Expanded too
child:
FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: 'https://www.xyzserver.com/images/dummyimage.png',
fit: BoxFit.scaleDown,
),
),
SizedBox(width: 64),
],
),
SizedBox(height: 28),
Text("stuff below the image"),
],
),
)
);
}
When using "Expanded" the image row/area is very tall vertically (the text "stuff below the image" is at the bottom of the page so the page jumps up when the image loads. When using "Flexible" the image row/area is somewhat smaller and the page jumps down when the image loads.
In the image I'm playing around with now, it's a horizontal image that is larger than the available screen space, so it will get scaled down. I guess I was thinking that since flutter can calculate the max width of what's available to the expanded/flexible, it should be able to calculate the height, but as I write this I'm thinking that's impossible since it doesn't know the height/width ratio so it can't predict the height.
How can I set this up so that images can be resized and show correctly and the page doesn't jump around? I can't imagine using fixed height/width settings is the way to go. Maybe my approach to images is all wrong and I should always use a set height/width although that can be rather difficult when people are allowed to upload their own images/etc.
Thanks!
Check this one
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Uint8List? imageData;
Future<Uint8List> dosometinhdd() async {
return (await rootBundle.load('assets/images/a.png')).buffer.asUint8List();
}
#override
void initState() {
dosometinhdd().then((value) {
setState(() {
imageData = value;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Welcome!'),
),
body: new SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height * 0.8,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
imageData != null
? Expanded(
child: FadeInImage.memoryNetwork(
placeholder: imageData!,
image:
'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1200px-Image_created_with_a_mobile_phone.png',
fit: BoxFit.scaleDown,
),
)
: Container(),
Text("stuff below the image"),
],
),
),
));
}

Dynamic size of container - Flutter

I'm new to flutter and came across an issue with Container widget's size that has Row and Column as it's child. I'm aiming to render a Column and Row widget with dynamic data. The code is as below.
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(35),
color: Colors.orange.shade400,
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15.0, horizontal: 25.0),
child: Column(
children: <Widget>[
Text("PEAK/THURSDAY"),
Text("\$24,355"),
weeklyExpenseBuilder(), // Row with Text widgets
],
),
),
)
Not fixing the size of the container allows it to take up all the screen space but fixing it's height leads to RenderFlex overflow error. Is there any way to let the Container widget take only as much space as it's children take.
The design that i'm aiming to looks something like this
The mainAxisSize property of a Row or Column is max by default.
Try setting mainAxisSize: MainAxisSize.min on both the row and column and adding some spacing.
You should always make give size related to width and height of the screen to make the app perfectly responsive
for example you can create a variable
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
and use it for you Container or fontsize for example
import 'package:flutter/material.dart';
class TestWidget extends StatefulWidget {
const TestWidget({Key? key}) : super(key: key);
#override
_TestWidgetState createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget> {
#override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Container(
height: height,
width: width / 2,
child: Text('test',
style: TextStyle(
fontSize: width * 0.035,
)),
);
}
}
And for avoiding overflow you can always user Wrap or Expanded(inside a row or column).

Why does Sliver App Bar's flexibleSpace parameter have to take a Widget with a const constructor?

I am trying to build a custom scroll view which contains a sliver app bar to achieve something similar to what's shown here:
https://medium.com/#diegoveloper/flutter-collapsing-toolbar-sliver-app-bar-14b858e87abe
However I want to have the word Search and below it I want 3 IconButtons Evenly spaced, when the page (CustomScrollView) is scrolled, I want the 3 IconButtons to be pinned to the top of the SliverAppBar and the Search Text to disappear...
I Tried to achieve the above via the following code:
class SearchPage extends StatelessWidget {
const SearchPage();
#override
Widget build(BuildContext context) {
return CustomScrollView(slivers: <Widget>[
const SliverAppBar(
pinned: true,
expandedHeight: 250.0,
flexibleSpace: _buildSliverAppBarFlex(),
);
}
Widget _buildSliverAppBarFlex() {
return Container(
child: Column(
children: <Widget>[
Text("Search", style: TextStyle(fontSize: 24.0,
color: Colors.white,
fontWeight: FontWeight.bold)),
Row(children: <Widget>[
IconButton(icon: Icon(Icons.flight)),
IconButton(icon: Icon(Icons.hotel)),
IconButton(icon: Icon(Icons.drive_eta))
])
],
)
);
}
}
However I get a warning that flexibleSpace must take a const constructor widget and that the _buildSilverAppBarFlex Widget I've made is not - I cannot add const or final to it either... Any ideas how I can achieve what I want?
The warning comes because you are using const ahead of your SliverAppBar, remove this, and warning will be gone.
So, instead of this
const SliverAppBar(...)
Use this.
SliverAppBar(...)
If you want to use const there, make sure your FlexibleSpaceBar is also a const then.