I am getting an error, The method '*' was called on null - flutter

I have created a button class that extends a stateless widget for creating a customized button widget. I have used this button to create buttons in a class and it worked perfectly fine. But, when i tried to create a button in an another class, using the same button widget, i got an error,'The method '*' was called on null and RenderFlex overflowed' which i could not get why is it appearing. Can somebody help me, what and where did i do the blunder.
This one is the button widget
import 'package:flutter/material.dart';
import 'package:group_project/ui/size_config.dart';
import 'package:group_project/widgets/responsive_widget.dart';
// Button Widget
class Button extends StatelessWidget {
final IconData icon;
final String btnName;
final double height;
final double width;
final Color buttonColor;
final Color iconColor;
final double iconSize;
final Color textColor;
final double btnTextSize;
Border border;
BorderRadius btnBorderRadius;
MainAxisAlignment mainAxisAlignment;
CrossAxisAlignment crossAxisAlignment;
Button({
#required this.icon,
#required this.btnName,
this.height,
this.width,
this.buttonColor,
this.iconColor,
this.textColor,
this.border,
this.mainAxisAlignment,
this.crossAxisAlignment,
this.btnTextSize,
this.iconSize,
this.btnBorderRadius,
});
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
height: height,
width: width,
decoration: BoxDecoration(
color: buttonColor,
border: border,
borderRadius: btnBorderRadius,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: mainAxisAlignment,
children: [
Text(
btnName,
style: TextStyle(
fontSize: btnTextSize * SizeConfig.textMultiplier,
color: textColor,
),
),
Icon(
icon,
color: iconColor,
size: iconSize * SizeConfig.imageSizeMultiplier,
),
],
),
),
);
}
}
This is the class where I got the error.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
import 'package:group_project/ui/size_config.dart';
import 'package:group_project/widgets/widgets.dart';
// import 'package:group_project/data/data.dart';
// import 'package:group_project/widgets/product_carousel_widget.dart';
class ProductsPage extends StatefulWidget {
#override
_ProductsPageState createState() => _ProductsPageState();
}
class _ProductsPageState extends State<ProductsPage> {
Size size;
bool visible = true;
void isVisible() {
if (visible == true) {
visible = false;
} else {
visible = true;
}
}
#override
Widget build(BuildContext context) {
size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Color(0xfff0f0f0),
body: ListView(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Container(
height: 233.33 * SizeConfig.heightMultiplier,
width: double.infinity,
color: Colors.blue,
child: Image(
image: AssetImage('images/jacket.jpg'),
fit: BoxFit.cover,
),
),
Stack(
children: [
// Products description
Visibility(
visible: visible,
child: Padding(
padding: const EdgeInsets.only(top: 40.0),
child: Container(
padding: EdgeInsets.fromLTRB(10.0, 40.0, 10.0, 10.0),
height: 400,
width: double.infinity,
decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(20.0),
// border: Border.all(color: Colors.blue),
color: Colors.blue,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Iphone Pro Max'
),
Text(
'Rs. 125000'
),
],
),
SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'(Used)'
),
Text(
'Condition: Good'
),
],
),
SizedBox(
height: 20.0,
),
Text(
'This is iphone 11 pro max, 64 GB variant. The size of the mobile phone is 6.5 inches. Released 2019, September ',
),
SizedBox(
height: 20.0,
),
Row(
children: [
// This is the button where exactly I am getting the error
Button(
height: 25 * SizeConfig.heightMultiplier,
width: 80,
icon: Icons.shopping_cart,
btnName: 'Add',
),
],
),
],
),
),
),
),
FlatButton(
padding: EdgeInsets.all(0),
onPressed: () {
setState(() {
isVisible();
});
},
child: Button(
icon: EvaIcons.chevronDown,
btnName: 'Show Description',
height: 25.0 * SizeConfig.heightMultiplier,
width: double.infinity,
buttonColor: Colors.blue,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
btnTextSize: 8.0,
iconSize: 20,
textColor: Colors.white,
iconColor: Colors.white,
// btnBorderRadius: BorderRadius.circular(0),
),
),
],
),
],
),
],
),
],
),
);
}
}

Wrap it with Expanded Widget when using inside a Row or Column
Expanded(
child: Button(
height: 25 * SizeConfig.heightMultiplier,
width: 80,
icon: Icons.shopping_cart,
btnName: 'Add',
),
),

Your Row has no defined height or width. Try wrapping your row in an Expanded widget.
This also why you're getting the null reference exception. You're sizeConfig (Which I assume is based off of MediaQuery.of(context).size) Gets it's context from it's parent widget and since a Row widget doesn't define (It is a flexible widget) height or width, it will return null for size. Expanded will tell the Row to set its size to all available space.

#override
Widget build(BuildContext context) {
return SingleChildScrollView(child: Container(...));}
surround your code with SingleChildScrollView that's why render flex error is showing
for the '*' is called on null error click on the run button at the bottom of android studio and look at the log and click the link with ProductPage.dart and it will take you to the line where the error happens

Try giving it a width or wrapping with a Expanded
It is given infinite width because MediaQuery is always given the context of it's parent, and in this scenario it gets it from Row widget which doesn't have a defined width. Neither does a Column widget have a defined height. That's why it's giving the error.
Wrapping it with Expanded widget will make the Row take all of free space.

Related

Stop wrap widget from expanding child widgets - Flutter

I have my custom Button widget in a container which width is defined by the width of its content (it can't be static). When I put that widget in a wrap widget it expands my custom Button to screen width, but if I put it in a row it wraps correctly and I can't figure out how to maintain wanted width of children inside the wrap widget. Here is the code below:
My Custom Button Widget:
class Button extends StatefulWidget {
final String imageAsset;
final String btnText;
final Color colorBegin;
final Color colorEnd;
const Button({Key? key, required this.imageAsset, required this.btnText, required this.colorBegin, required this.colorEnd}) : super(key: key);
#override
State<Button> createState() => _ButtonState();
}
class _ButtonState extends State<Button> {
Variables variables = Variables();
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [widget.colorBegin, widget.colorEnd]
),
borderRadius: BorderRadius.all(Radius.circular(variables.radius(context, 16)))
),
child: Row(
children: [
Image.asset(
widget.imageAsset,
height: variables.height(context, 5),
width: variables.height(context, 5),
),
SizedBox(width: variables.width(context, 3)),
Text(
widget.btnText,
style: TextStyle(
fontFamily: 'LeagueSpartanRegular',
fontSize: variables.height(context, 2.5),
color: Color(0xFF0B182A),
),
),
SizedBox(width: variables.width(context, 4)),
],
),
);
}
}
My wrap widget:
class _ButtonListState extends State<ButtonList> {
#override
Widget build(BuildContext context) {
return Wrap(
alignment: WrapAlignment.center,
runSpacing: 20,
children: const [
Button(
btnText: 'Little Friend',
imageAsset: 'assets/images/icon_little_friend.png',
colorBegin: Color(0xFFb3d7a4),
colorEnd: Color(0xFFb0caaa),
),
Button(
btnText: 'Little Friend',
imageAsset: 'assets/images/icon_little_friend.png',
colorBegin: Color(0xFFb3d7a4),
colorEnd: Color(0xFFb0caaa),
),
Button(
btnText: 'Little Friend',
imageAsset: 'assets/images/icon_little_friend.png',
colorBegin: Color(0xFFb3d7a4),
colorEnd: Color(0xFFb0caaa),
),
Button(
btnText: 'Little Friend',
imageAsset: 'assets/images/icon_little_friend.png',
colorBegin: Color(0xFFb3d7a4),
colorEnd: Color(0xFFb0caaa),
),
],
);
}
}
And my home screen:
class _HomeWidgetState extends State<HomeWidget> {
Variables variables = Variables();
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: variables.height(context, 7)),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/bg_main.png"),
fit: BoxFit.cover,
),
),
child: Column(
children: [
TextCatalogue(),
SizedBox(height: variables.height(context, 4)),
Expanded(child: Stack(
children: [
WhiteBackgroundHome(),
ButtonList(),
]
)
),
],
),
);
}
}
Problem
This is the result when I replace wrap with row, the children aren't expanded
I tried placing it out of the expanded widget on the home screen, tried deleting everything on the home screen and returning only the wrap widget still get the same result.
It fixes the problem if I define the width of my custom button widget, but that is not the solution because the buttons will have different width depending on the text inside.
Try adding this line for your Button widget.
class _ButtonState extends State<Button> {
Variables variables = Variables();
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [widget.colorBegin, widget.colorEnd]
),
borderRadius: BorderRadius.all(Radius.circular(variables.radius(context, 16)))
),
child: Row(
mainAxisSize: MainAxisSize.min, // ++++++++++++++++
children: [
Image.asset(
widget.imageAsset,
height: variables.height(context, 5),
width: variables.height(context, 5),
),
SizedBox(width: variables.width(context, 3)),
Text(
widget.btnText,
style: TextStyle(
fontFamily: 'LeagueSpartanRegular',
fontSize: variables.height(context, 2.5),
color: Color(0xFF0B182A),
),
),
SizedBox(width: variables.width(context, 4)),
],
),
);
}
}
You want the width of each button to be the sum of widths of its children. In your Button widget's build function. Add mainAxisSize: MainAxisSize.min to the Row widget.
From the docs:
The width of the Row is determined by the mainAxisSize property. If the mainAxisSize property is MainAxisSize.max, then the width of the Row is the max width of the incoming constraints. If the mainAxisSize property is MainAxisSize.min, then the width of the Row is the sum of widths of the children (subject to the incoming constraints).
//...
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset(
widget.imageAsset,
height: variables.height(context, 5),
width: variables.height(context, 5),
),
//...

RenderFlex overflow error displayed while using the card type class inside a container - Flutter

I'm trying to display 2 cards inside a Container, but I'm getting the same RenderFlex error.
Can anyone help me out with this?
Here is the complete error:
════════ Exception caught by rendering library ═════════════════════════════════
A RenderFlex overflowed by 8.0 pixels on the bottom.
The relevant error-causing widget was: Column
lib\…\widgets\card_main.dart:60
Here is my code:
card_main.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pfe_app/screens/user_related/bilan_patient_screen.dart';
import 'package:pfe_app/screens/user_related/profile_screen.dart';
import '../constants.dart';
import 'custom_clipper.dart';
class CardMain extends StatelessWidget {
final ImageProvider image;
final String title;
final String value;
final String unit;
final Color color;
CardMain(
{Key? key,
required this.image,
required this.title,
required this.value,
required this.unit,
required this.color})
: super(key: key);
#override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topLeft,
child: Container(
margin: const EdgeInsets.only(right: 15.0),
width: ((MediaQuery.of(context).size.width -
(Constants.paddingSide * 2 + Constants.paddingSide / 2)) /
2),
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
shape: BoxShape.rectangle,
color: color,
),
child: Material(
child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
child: Stack(
overflow: Overflow.clip,
children: <Widget>[
Positioned(
child: ClipPath(
clipper: MyCustomClipper(clipType: ClipType.semiCircle),
child: Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
color: Colors.black.withOpacity(0.03),
),
height: 120,
width: 120,
),
),
),
Padding(
padding: EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Icon and Hearbeat
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Image(width: 32, height: 32, image: image),
SizedBox(
width: 10,
),
Expanded(
child: Text(
title,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13, color: Constants.textDark),
),
),
],
),
SizedBox(height: 10),
Text(
value,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.w900,
color: Constants.textDark,
),
),
Text(
unit,
style:
TextStyle(fontSize: 15, color: Constants.textDark),
),
],
),
)
],
),
onTap: () {
debugPrint("CARD main clicked. redirect to details page");
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProfileScreen()),
);
},
),
color: Colors.transparent,
),
),
);
}
}
and here is the part in which i'm using that card class:
Container(
height: 140,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
CardMain(
image: AssetImage('assets/heartbeat.png'),
title: "Hearbeat",
value: "66",
unit: "bpm",
color: Constants.lightGreen,
),
CardMain(
image: AssetImage('assets/blooddrop.png'),
title: "Blood Pressure",
value: "66/123",
unit: "mmHg",
color: Constants.lightYellow)
],
),
),
Each Card could extend to over 70 pixels and you limit your Container to 140. Nothing I see in your CardMain limits its height to 70. So either increase that height or limit your CardMain. Based on my math of 40+32+10 plus two rows of Text, you should have overflowed more than 8, but maybe your text was empty. Even empty text will take height...use
unit == '' ? Container() : Text(unit)
to get rid of empty text spacing.

Flutter Wrap Widget does not expand itself

I'm trying to create a calendar and I'm using Wrap widget to display days inside calendar. But I faced a problem. Wrap widget does not expand itself to every side that's why overflow happens. This is my code:
return Container(
height: MediaQuery.of(context).size.height * 0.40,
width: MediaQuery.of(context).size.width / 2,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(46.0),
color: Color(0xFFD6D6D6),
boxShadow: [
BoxShadow(
color: Color(0xFF000000).withOpacity(0.16),
offset: Offset(0, 10),
blurRadius: 20.0,
),
],
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(width: 8.0),
GestureDetector(
onTap: () {},
child: Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
),
Text(
'${getMonthName(initialDate.month)}',
style: GoogleFonts.baloo(
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.w400,
),
),
GestureDetector(
onTap: () {},
child: Icon(
Icons.arrow_forward_ios,
color: Colors.white,
),
),
SizedBox(width: 8.0),
],
),
Container(
height: MediaQuery.of(context).size.height * 0.25,
width: MediaQuery.of(context).size.width / 2.5,
child: Row(
children: [
Wrap(
alignment: WrapAlignment.start,
direction: Axis.horizontal,
spacing: 2.0,
children: dayList == null
? SizedBox()
: dayList.map((e) {
return DaysContainer(
number: e,
);
}).toList(),
),
],
),
),
],
),
);
When I remove upper Row in Wrap, this time widget only goes to vertical even though I define Axis.horizontal.
DaysContainer class:
class DaysContainer extends StatelessWidget {
const DaysContainer({Key key, this.number, this.isAvailable})
: super(key: key);
final String number;
final bool isAvailable;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Color(0xFFFFFFFF),
),
child: Center(
child: Text(
number,
style: GoogleFonts.baloo(
fontSize: 30.0,
color: Color(0xFFBFBFBF),
fontWeight: FontWeight.w400,
),
),
),
);
}
}
This is the result in Flutter Web:
Expected result:
Can anyone help me to figure out what is the problem in Wrap widget?
Please change your code with the following changes:
Removed Row widget outside Wrap
Defined your width of DaysContainer. Currently, the width of Container in DaysContainer has full width of parent widget. That is the reason why your time widget goes to vertical even though you define Axis.horizontal in Wrap widget.
By the way, you can add the properties runSpacing and spacing to your Wrap widget to give more space between your items in horizontal and vertical instead of using padding.
try to change to:
Container(
height: MediaQuery.of(context).size.height * 0.25,
width: MediaQuery.of(context).size.width / 2.5,
child: Wrap(
alignment: WrapAlignment.start,
direction: Axis.horizontal,
spacing: 2.0,
children: dayList == null
? SizedBox()
: dayList.map((e) {
...
class DaysContainer extends StatelessWidget {
const DaysContainer({Key key, this.number, this.isAvailable})
: super(key: key);
final String number;
final bool isAvailable;
#override
Widget build(BuildContext context) {
return Container(
width: 20,
height: 20,
margin: EdgeInsets.only(bottom: 2.0),
padding: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Color(0xFFFFFFFF),
),
child: Center(
child: Text(
number,
style: GoogleFonts.baloo(
fontSize: 30.0,
color: Color(0xFFBFBFBF),
fontWeight: FontWeight.w400,
),
),
),
);
}
}

How to prevent Row from taking all available width?

I have one problem with my CustomChip :
I need to wrap the card to fit the content only.
However, I have a second requirement: The long text should overflow fade.
When I fixed the second problem, this issue started to occur when I added Expanded to wrap the inner Row
I don't understand why the inner Row also seems to expand although its mainAxisSize is already set to min
Here is the code:
The screen:
import 'package:flutter/material.dart';
import 'package:app/common/custom_chip.dart';
class RowInsideExpanded extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
),
),
width: 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildChip('short'),
_buildChip('looooooooooooooooooooooongg'),
],
),
),
),
);
}
_buildChip(String s) {
return Row(
children: [
Container(
color: Colors.red,
width: 15,
height: 15,
),
Expanded(
child: CustomChip(
elevation: 0.0,
trailing: Container(
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
),
child: Icon(Icons.close),
),
onTap: () {},
height: 42.0,
backgroundColor: Colors.black12,
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
s,
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
),
),
],
);
}
}
And the CustomChip
import 'package:flutter/material.dart';
class CustomChip extends StatelessWidget {
final Widget leading;
final Widget trailing;
final Widget title;
final double height;
final double elevation;
final Color backgroundColor;
final VoidCallback onTap;
const CustomChip({
Key key,
this.leading,
this.trailing,
this.title,
this.backgroundColor,
this.height: 30.0,
this.elevation = 2.0,
this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Card(
elevation: elevation,
color: backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: InkWell(
onTap: onTap,
child: Container(
height: height,
child: Padding(
padding: const EdgeInsets.only(left: 5.0, right: 5.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
leading ?? Container(),
SizedBox(
width: 5.0,
),
Flexible(
child: title,
fit: FlexFit.loose,
),
SizedBox(
width: 5.0,
),
trailing ?? Container(),
],
),
),
),
),
);
}
}
Look for "MainAxisSize" property and set to "MainAxisSize.min"
Instead of Expanded, just replace it with a Flexible that's because Expanded inherits Flexible but set the fit proprety to FlexFit.tight
When fit is FlexFit.tight, the box contraints for any Flex widget descendant of a Flexible will get the same box contraints. That's why your Row still expands even though you already set its MainAxisSize to min.
I changed your code to print the box contraints using a the LayoutBuilder widget.
Consider your code with Expanded:
import 'package:flutter/material.dart';
class RowInsideExpanded extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 1.0,
),
),
width: 200.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_buildChip('short'),
SizedBox(
height: 5,
),
_buildChip('looooooooooooooooooooooongg'),
],
),
),
),
);
}
_buildChip(String s) {
return Row(
children: [
Container(
color: Colors.red,
width: 15,
height: 15,
),
Expanded(
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
print("outter $constraints");
return Container(
color: Colors.greenAccent,
child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
print("inner $constraints");
return Row(
mainAxisSize: MainAxisSize.min, // this is ignored
children: <Widget>[
SizedBox(
width: 5.0,
),
Flexible(
fit: FlexFit.loose,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
s,
softWrap: false,
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
),
SizedBox(
width: 5.0,
),
Container(
decoration: BoxDecoration(
color: Colors.grey,
shape: BoxShape.circle,
),
child: Icon(Icons.close),
),
],
);
}),
);
}),
),
],
);
}
}
It prints
I/flutter ( 7075): outter BoxConstraints(w=183.0, 0.0<=h<=Infinity)
I/flutter ( 7075): inner BoxConstraints(w=183.0, 0.0<=h<=Infinity)
(Look at the width in w, it constrained to be 183.0 for both outter and inner Row)
Now I changed the Expanded to Flexible and check the logs:
I/flutter ( 7075): outter BoxConstraints(0.0<=w<=183.0, 0.0<=h<=Infinity)
I/flutter ( 7075): inner BoxConstraints(0.0<=w<=183.0, 0.0<=h<=Infinity)
(Look at the width in w, it constrained to between zero and 183.0 for both outter and inner Row)
Now your widget is fixed:

How to limit draggable scrollable sheet to take height according to its child height in flutter?

I am using draggableScrollableSheet. I am giving these parameters
DraggableScrollableSheet(initialChildSize: 0.4,maxChildSize: 1,minChildSize: 0.4,builder: (BuildContext context, ScrollController scrollController) {
return SingleChildScrollView(controller: scrollController,
child: Theme(
data: Theme.of(context).copyWith(canvasColor: Colors.transparent),
child: Opacity(
opacity: 1,
child: IntrinsicHeight(
child: Column(mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(height: 10,),
Container(
margin: EdgeInsets.only(right: 300),
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Colors.blue,
width: 3,
style: BorderStyle.solid),
),
),
),
Card(
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
S
.of(context)
.we_have_found_you_a_driver,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold),
),
SizedBox(
height: 10,
),
Text(S
.of(context)
.driver_is_heading_towards +
' ${widget.order.foodOrders.first.food.restaurant.name}')
],
),
),
],
),
elevation: 5,
),
SizedBox(height: 10,),
Card(
elevation: 5,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
CircleAvatar(
radius: 50.0,
backgroundColor: Colors.white,
child:
Image.asset(
'assets/img/image_not_available.jpg'),
),
Expanded(
child: Column(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: Text('Test',
textAlign: TextAlign.start,
style: new TextStyle(
color: Colors.black,
fontSize: 16.0,
)),
),
Icon(Icons.star, color: Colors.yellow.shade700,)
],
),
SizedBox(height: 30,),
Row(mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
child: Container(
child: Text('Mobile number',
textAlign: TextAlign.start,
style: new TextStyle(
color: Colors.black,
fontSize: 16.0,
)),
),
),
Icon(Icons.phone,),
SizedBox(width: 10,),
Icon(Icons.message),
],
),
],
),
)
]),
),
SizedBox(height: 10,),
Card(
child: Align( alignment: Alignment(-1,1),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
S
.of(context)
.you_ordered_from + ' ${widget.order.foodOrders.first.food.restaurant.name}',
style: TextStyle(
color: Colors.grey,
),
),
SizedBox(
height: 5,
),
Column(children: List.generate(widget.order.foodOrders.length,(index) {
return Text(
'${widget.order.foodOrders[index].food.name}'
);
},),),
Row(
children: <Widget>[
Column(crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('See details', style: TextStyle(fontWeight: FontWeight.bold,color: Colors.blue),),
],
),
],
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
SizedBox(height: 40,),
Row(
children: <Widget>[
Icon(Icons.monetization_on),
Text(widget.order.foodOrders
.first.price
.toString()),
],
),
],
),
),
],
),
),
elevation: 5,
),
],
),
),
),
),
)
and I also used a single child scroll view and column so that I can show my cards in that column of draggableScrollableSheet. But I want draggableScrollableSheet to take height dynamically instead of defining size. Like now I want to show only 2 to 3 cards and that is taking full screen. But I want it to take the minimum height of the screen. How can we achieve this?
I was struggling with this for a while, and then discovered that the correct way to achieve this is to use ClampingScrollPhysics as the physics parameter of the scroll view.
https://api.flutter.dev/flutter/widgets/ClampingScrollPhysics-class.html
I'm a week into Flutter but I found a solution to this. It might be substandard so correct me if I'm wrong.
So what I've done is create a variable called bsRatio for the bottom sheet. This is will be the height of the child view/widget (or bottom sheet content) divide by the height of the parent/screen. This ratio should be set to the maxChildSize and probably even the initialChildSize of your DraggableScrollableSheet.
So in your parent widget or Widget State class add something like this.
class ParentWidget extends StatefulWidget {
ParentWidget({Key? key}) : super(key: key);
#override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
var bsRatio = 0.4; // Set an initial ratio
#override
Widget build(BuildContext context) {
// The line below is used to get status bar height. Might not be required if you are not using the SafeArea
final statusBarHeight = MediaQuery.of(context).viewPadding.top;
// If you are not using SafeArea Widget you can skip subtracting status bar height from the Window height
final windowHeight = MediaQuery.of(context).size.height - statusBarHeight;
// This below is a callback function that will be passed to the child Widget of the DraggableScrollableSheet ->
childHeightSetter(childHeight) {
// setState rebuilds the UI with the new `bsRatio` value
setState(() {
// The new bottom sheet max height ratio is the height of the Child View/Widget divide by the screen height
bsRatio = childHeight / windowHeight;
});
}
return Scaffold(
backgroundColor: Colors.black12,
body: SafeArea(
child: Stack(
children: [
const SomeBackgroundView(),
DraggableScrollableSheet(
initialChildSize: bsRatio, // here you set the newly calculated ratio as the initial height of the Bottom Sheet
minChildSize: 0.2,
maxChildSize: bsRatio, // here you set the newly calculated ratio as the initial height of the Bottom Sheet
snap: true,
builder: (_, controller) {
return LayoutBuilder(builder: (_, box) {
// Added a container here to add some curved borders and decent looking shadows via the decoration property
return Container(
child: SingleChildScrollView(
controller: controller,
// The child view/widget `MyBottomSheet` below is the actual bottom sheet view/widget
child: MyBottomSheet(childHeightSetter: childHeightSetter),
),
decoration: const BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 5.0,
spreadRadius: 2.0
)
],
borderRadius: BorderRadius.all(Radius.circular(20.0))
),
);
});
},
),
],
),
),
);
}
}
And this would be your child view/widget (also your BottomSheet view/widget)
class MyBottomSheet extends StatefulWidget {
// This below is the local callback variable. The `?` is because it may not be set if not required
final ValueSetter<double>? childHeightSetter;
const MyBottomSheet({Key? key, this.childHeightSetter}) : super(key: key);
#override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _LoginBottomSheetState extends State<LoginBottomSheet> {
// bsKey is the key used to reference the Child widget we are trying to calculate the height of. Check the `Card` container below
GlobalKey bsKey = GlobalKey();
// this method will me used to get the height of the child content and passed to the callback function so it can be triggered and the ratio can be calculated and set in the parent widget
_getSizes() {
final RenderBox? renderBoxRed =
bsKey.currentContext?.findRenderObject() as RenderBox?;
final cardHeight = renderBoxRed?.size.height;
if (cardHeight != null)
super.widget.childHeightSetter?.call(cardHeight);
}
// This is the function to be called after the Child has been drawn
_afterLayout(_) {
_getSizes();
}
#override
void initState() {
super.initState();
// On initialising state pass the _afterLayout method as a callback to trigger after the child Widget is drawn
WidgetsBinding.instance?.addPostFrameCallback(_afterLayout);
}
#override
Widget build(BuildContext context) {
return Card(
key: bsKey, // This is the key mentioned above used to calculate it's height
color: Colors.white,
shadowColor: Colors.black,
elevation: 40.0,
margin: EdgeInsets.zero,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0))),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Random children for bottom sheet content
const SizedBox(height: 10.0),
Center(
child: Container(
child: const SizedBox(width: 40.0, height: 5.0),
decoration: BoxDecoration(
color: Colors.grey[400],
borderRadius: BorderRadius.circular(5.0)
),
),
),
const SizedBox(height: 10.0),
const AnotherBottomSheetContentView()
],
),
);
}
}
the initialChildSize is the height of your ScrollView before its actually scrolled, so that means you can actually decide what it would look like.
here is an example![the draggable scrollsheet here has initialChildSize: 0.1,maxChildSize: 1,minChildSize: 0.1,
]1