I am opening a bottom model sheet, and want to implement a functionality that whenever I click on a icon, I get a snackbar. So i implemented it, but whenever I am clicking on the button, snackbar is coming under the bottom modal sheet, like when you lower the bottom model sheet, you can see snackbar popped there in previous screen. I want that snackbar should show above the modal sheet, visible to user while sheet is up. Please help me on this.
Here is the code -
class RouteItems extends StatelessWidget {
final int index;
final NodeElement data;
RouteItems({required this.index, required this.data});
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
SvgPicture.asset(
'assets/icons/road-straight-line-top-view.svg',
height: 15,
width: 80,
),
SvgPicture.asset(
filterRoutesIcon("${data.node?.type}"),
height: 30,
width: 30,
),
SvgPicture.asset(
'assets/icons/road-straight-line-top-view.svg',
height: 15,
width: 80,
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Container(
//height: 60,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: MediaQuery.of(context).size.width*0.625,
child: Text(
'${data.node?.name}',
style: TextStyle(fontSize: 12.0),
//overflow: TextOverflow.ellipsis,
),
),
Text(
data.eta!.getFormattedDate('hh:mm a, d MMM'),
style: TextStyle(fontSize: 10.0, color: colorDarkGrey),
)
],
),
),
),
],
),
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Wrap(
children: [
Text(
'Bus is scheduled to arrive at ${data.eta!.getFormattedDate('hh:mm a, d MMM')} Bus is scheduled to depart at ${data.etd!.getFormattedDate('hh:mm a, d MMM')}'
),
],
),
),
);
},
child: Column(
children: [
Icon(
Icons.timer,
size: MediaQuery.of(context).size.width*0.04,
),
Text(
getStoppageTime(data.stoppage??0),
style: TextStyle(
fontSize: 10,
color: popUpLightTextColor,
),
),
],
),
),
),
],
),
);
}
}
Related
I am designing a screen with two main sections:
A carousel slider with a TextField below it
A button
I want the button to be at the bottom of the screen.
To achieve this, I have wrapped the column for 1. in a Flexible widget and set the mainAxisSize for the Column to max, and the mainAxis size for the Column containing the button to min.
Now when I click on the TextField, the keyboard appears, and I receive a Bottom Overflowed error with the Button appearing on top of the TextField.
How do I ensure that the Button stays at the bottom of the screen when the keyboard appears? I have tried wrapping both the Columns in another Column which in turn had been wrapped by a SingleChildScrollView widget, but that overrides the MainAxisSize.max property apparently, and renders the lower Column (containing the Button) just below the upper Column as seen below.
My Code:
class SigninScreen extends StatefulWidget {
const SigninScreen({super.key});
#override
State<SigninScreen> createState() => _SigninScreenState();
}
class _SigninScreenState extends State<SigninScreen> {
int _currentCarouselIndex = 0;
List<Widget> indicators(imagesLength, currentIndex) {
return List<Widget>.generate(imagesLength, (index) {
return Container(
margin: EdgeInsets.symmetric(
vertical: 1.h,
horizontal: 2,
),
width: currentIndex == index ? 15 : 10,
height: 3,
decoration: BoxDecoration(
color: currentIndex == index ? primary : grey,
borderRadius: const BorderRadius.all(
Radius.circular(2),
),
),
);
});
}
TextEditingController phoneController = TextEditingController();
#override
void dispose() {
phoneController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: GestureDetector(
onTap: (){ FocusManager.instance.primaryFocus?.unfocus();},
behavior: HitTestBehavior.opaque,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
fit: FlexFit.loose,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
CarouselSlider(
items: carouselImageList.map<Widget>((i){
return Builder(
builder: (context){
return Container(
width: 100.w,
height: 83.w,
decoration: BoxDecoration(
image: DecorationImage(image: AssetImage(i), fit: BoxFit.fill),
),
);
}
);
}).toList(),
options: CarouselOptions(
height: 83.w,
aspectRatio: 1/0.83,
autoPlay: true,
autoPlayInterval: const Duration(seconds: 3),
initialPage: 0,
viewportFraction: 1,
onPageChanged: (index, timed) {
setState(() {
_currentCarouselIndex = index;
});
}
),
),
SizedBox(height: 1.h,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators(
carouselImageList.length, _currentCarouselIndex),
),
SizedBox(height: 2.h,),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(isEnglish ? "Enter your phone number" : "अपना फ़ोन नंबर दर्ज करें", style: globalTextStyle.copyWith(fontSize: 5.w, fontWeight: FontWeight.bold),),
],
),
SizedBox(height: 1.h),
PhoneNumberField(phoneController: phoneController),
SizedBox(height: 1.h),
Text(isEnglish ? "OTP will be sent on this number." : "इस नंबर पर ओटीपी भेजा जाएगा।", style: globalTextStyle.copyWith(fontSize: 3.w,),),
],
),
),
],
),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(width: 90.w, height: 15.w, color: primary, onTap: (){
// Navigator.pushNamed(context, otp);
(phoneController.text.length == 10) ?
Navigator.push(context, MaterialPageRoute(builder: (context) =>
OTPScreen(phoneNumber: "+91${phoneController.text}")))
: ShowSnackbar.showSnackBar(context, isEnglish ? "Enter a valid 10 digit phone number." : "एक मान्य 10 अंकों का फ़ोन नंबर दर्ज करें।");
}, text: isEnglish ? "Get OTP" : "ओटीपी प्राप्त करें", fontColor: white, borderColor: primary,),
SizedBox(height: 1.h,),
Text(isEnglish ? "By signing up, you agree to our Terms and Services" : "साइन अप करके, आप हमारी शर्तों से सहमत होते हैं और सेवाएं", style: globalTextStyle.copyWith(fontSize: 2.5.w,),),
SizedBox(height: 2.h,),
],
),
],
),
),
),
),
);
}
}
How do I get the Button to stay at the bottom of the screen even when the keyboard appears?
Remove the Flexible and try the below code.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusManager.instance.primaryFocus?.unfocus();
},
behavior: HitTestBehavior.opaque,
child: SingleChildScrollView(
child: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
children: [
CarouselSlider(
items: carouselImageList.map<Widget>((i) {
return Builder(builder: (context) {
return Container(
width: 100.w,
height: 100.w,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(i), fit: BoxFit.fill),
),
);
});
}).toList(),
options: CarouselOptions(
height: 83.w,
aspectRatio: 1 / 0.83,
autoPlay: true,
autoPlayInterval: const Duration(seconds: 3),
initialPage: 0,
viewportFraction: 1,
onPageChanged: (index, timed) {
setState(() {
_currentCarouselIndex = index;
});
}),
),
SizedBox(
height: 1.h,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: indicators(
carouselImageList.length, _currentCarouselIndex),
),
SizedBox(
height: 2.h,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 5.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
"Enter your phone number",
style: TextStyle(
fontSize: 5.w, fontWeight: FontWeight.bold),
),
],
),
SizedBox(height: 1.h),
TextFormField(
controller: phoneController,
keyboardType: TextInputType.phone,
),
SizedBox(height: 1.h),
Text(
"OTP will be sent on this number.",
style: TextStyle(
fontSize: 3.w,
),
),
],
),
),
Expanded(
child: Container(),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomButton(
width: 90.w,
height: 15.w,
color: primary!,
onTap: () {},
text: "Get OTP",
fontColor: white!,
borderColor: primary!,
),
SizedBox(
height: 1.h,
),
Text(
"By signing up, you agree to our Terms and Services",
style: TextStyle(
fontSize: 2.5.w,
),
),
SizedBox(
height: 2.h,
),
],
),
],
),
),
),
),
),
);
}
In your Scaffold set resizeToAvoidBottomInset: property to false I think this will help. Otherwise I observed that the render overflow error is from the column that contains the PhoneNumberField so try Increasing the height of the SizedBox after the PhoneNumberField if the first method doesn't work.
I have this class State:
class _ItemCardState extends State<ItemCard> {
double imgSize = 30;
Axis expanded = Axis.horizontal;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
expanded =
expanded == Axis.horizontal ? Axis.vertical : Axis.horizontal;
imgSize = imgSize == 30 ? 200 : 30;
});
},
child: Card(
margin: const EdgeInsets.all(5.0),
child: Padding(
padding: const EdgeInsets.all(15),
child: Flex(
direction: expanded,
children: [
Image.network(
'http://cdn.shopify.com/s/files/1/0565/0697/4379/articles/Cafe-expresso-sin-maquina_1200x1200.jpg?v=1621619617',
width: imgSize,
),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.product['name'],
style: const TextStyle(fontSize: 20)),
Text(widget.product['price'] + ' \$',
style: const TextStyle(fontSize: 15)),
],
),
Text(widget.product['ingredients'],
style: const TextStyle(fontSize: 15, color: Colors.grey)),
],
),
],
),
),
),
);
}
}
I want the Flex Widget change direction onTap, it works.
But the column inside is not taking all space avaible in the crossAxis.
If I put an Expanded Widget it stops working,...
I've tried Flexibles, but somehow it didnt work.
I used ListTiles also, but I couldnt make it work.
Any idea on how to do it?
well. I resolved it putting the Flex Widget inside a SizedBox and then I was able to use Flexible>fit:FlexFit.tigth:
SizedBox(
height: 300,
child: Flex(
direction: expanded,
children: [
Image.network(
'http://cdn.shopify.com/s/files/1/0565/0697/4379/articles/Cafe-expresso-sin-maquina_1200x1200.jpg?v=1621619617',
width: imgSize,
),
Flexible(
fit: FlexFit.tight,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.product['name'],
style: const TextStyle(fontSize: 20)),
Text(widget.product['price'] + ' \$',
style: const TextStyle(fontSize: 15)),
],
),
Text(widget.product['ingredients'],
style: const TextStyle(
fontSize: 15, color: Colors.grey)),
],
),
)
],
),
),
I receive a list of images from api call, I need to layout these images like on this example, I have already implemented this logic, but I think it is redundant, and can be done easier, without hard-coded which item need to be first, last, etc.. and I think that widget tree could be less. How I can improve this code?
my emplementation:
List<Widget> _listImages() {
List<Widget> imagesList = [];
for (int i = 0; i < images.length; i++) {
imagesList.add(
Expanded(
child: Padding(
padding: const EdgeInsets.all(2.0),
child: GestureDetector(
onTap: () {
open(context);
},
child: child: NetworkImage(images[i]),
),
),
);
);
}
return imagesList;
}
Widget build(BuildContext context) {
return Card(...
Column(//Image layout
children: [
Row(
children: [
_listImages().first,
],
),
Container(
height: 110,
child: Row(
children: [
Expanded(
flex: 2,
child: Row(
children: _listImages().getRange(1, 3).toList(),
),
),
Expanded(
child: Stack(children: [
Row(
children: [
_listImages().elementAt(3),
],
),
IgnorePointer(
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
color: Colors.black54,
child: Center(
child: Text(
'+ ${_listImages().length - 3}',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.w500),
),
),
),
),
),
]),
),
],
),
),
],
)
....
}
You could try Gridview. You can use main axis spacing and cross axis spacing to change the distance between grid tiles.
https://www.geeksforgeeks.org/flutter-gridview/
I want to display a List and beneath it a Persistent footer, a Column with some rows. I use persistentFooterButtons of Scaffold.
The closest to what I get is this:
But I am unable to align the fields to the right.
When I work with Align or Spacer, the Widgets disappear.
The content of persistentFooterButtons.
FittedBox(
child: Column(
children: <Widget>[
FlatButton(
onPressed: () {
Navigator.pushNamed(context, RouteName.BAUSTELLEN);
},
child: Align(
alignment: Alignment.bottomLeft,
child: Text('Bestellen'),
),
),
Row(
children: <Widget>[
Text('$priceInfo '),
MyFutureBuilder(
future: sum,
builder: (context, double sum) {
var mySum = formatDoubleNumber(sum);
return Text('$mySum');
},
),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
Row(
children: <Widget>[
Text('Ihr Einkaufsrahmen '),
Text(
'$einkaufsrahmen',
style: TextStyle(
color: einkaufsrahmen == 0 ? Colors.red : Colors.black),
),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
],
),
);
If I put the elements directly to persitentFooterButtons, this is what I get, the text is scattered around and my list is not shown.
and the Code
Scaffold(
body: WarenkorbListe(),
persistentFooterButtons: <Widget>[
// WarenkorbFooter(),
FlatButton(
onPressed: () {
Navigator.pushNamed(context, RouteName.BAUSTELLEN);
},
child: Align(
alignment: Alignment.bottomLeft,
child: Text('Bestellen'),
),
),
Row(
children: <Widget>[
Text('$priceInfo '),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
Row(
children: <Widget>[
Text('Ihr Einkaufsrahmen '),
Text(
'$einkaufsrahmen',
style: TextStyle(
color: einkaufsrahmen == 0 ? Colors.red : Colors.black),
),
Container(
width: ImpexStyle.horizontalPadding,
),
],
),
],
);
Try to align with your column instead
FittedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end, // this
children: <Widget>[
I have Stepper in my app, and I have problems with placing textfield on screen, when I want to text some text in textfield, appears keyboard and over it shows me that:
A RenderFlex overflowed by 139 pixels on the bottom.
I read some articles and understood, that I have to use FittedBox, but I dunno how to use it with best way. How can I reach my goal?
Code:
#override
Widget build(BuildContext context) {
globalHeight = (MediaQuery.of(context).size.height) * 0.85;
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
decoration: BoxDecoration(color: colorsBackround[_currentPage]),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: globalHeight,
child: PageView(
physics: ClampingScrollPhysics(),
controller: _pageController,
onPageChanged: (int page) {
setState(() {
_currentPage = page;
});
},
children: <Widget>[
// some code
Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Image(
image: AssetImage(
itemIcon[_currentPage],
),
height: 300.0,
width: 300.0,
),
Text(
'Укажите ваш возраст',
style: kTitleStyle,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
height: 50.0,
child: Padding(
padding: EdgeInsets.only(
top: 20.0,
left: 20,
right: 20,
bottom: MediaQuery.of(context)
.viewInsets
.bottom),
child: TextField(
controller: ageController,
keyboardType: TextInputType.number,
onChanged: (text) {
setState(() {
if (text.isNotEmpty) {
inputs[1] = true;
} else {
inputs[1] = false;
}
});
},
decoration: InputDecoration(
labelText: 'Возраст',
),
style: TextStyle(fontSize: 18.5),
)),
),
],
),
),
),
//some code
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPageIndicator(),
),
_currentPage != _numPages - 1
? Expanded(
child: Container(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Align(
alignment: FractionalOffset.bottomLeft,
child: FlatButton(
onPressed: () {
_pageController.previousPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.arrow_back,
color: Colors.white,
size: 26.0,
),
SizedBox(width: 10.0),
Text(
'Назад',
style: TextStyle(
fontFamily: 'Century Gothic',
color: Colors.white,
fontSize: 14.5,
),
),
],
),
),
)),
Expanded(
child: Align(
alignment: FractionalOffset.bottomRight,
child: FlatButton(
onPressed: () {
_pageController.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Дальше',
style: TextStyle(
fontFamily: 'Century Gothic',
color: Colors.white,
fontSize: 14.5,
),
),
SizedBox(width: 10.0),
Icon(
Icons.arrow_forward,
color: Colors.white,
size: 26.0,
),
],
),
),
)),
],
)))
: Text(''),
],
),
),
),
),
bottomSheet: _currentPage == _numPages - 1
? Container(
height: 75.0,
width: double.infinity,
color: Theme.of(context).scaffoldBackgroundColor,
child: GestureDetector(
onTap: () => print('Get started'),
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 15.0),
child: Text(
'Начать',
style: TextStyle(
fontFamily: 'Century Gothic',
color: Colors.white,
fontSize: 21.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
)
: Text(''),
);
}
}
There is no direct solution to prevent overflowing issues, it depends on your current code. So, here you use
Add to your Scaffold
resizeToAvoidBottomInset: false
Wrap your widget in SingleChildScrollView
SingleChildScrollView(
child: YourColumn(),
)
That happens because when opening the keyboard, the body is resized to avoid the keyboard appear over the text field, and since your content isn't scrollable the content of the body gets overflowed. Check this property of the Scaffold:
/// If true the [body] and the scaffold's floating widgets should size
/// themselves to avoid the onscreen keyboard whose height is defined by the
/// ambient [MediaQuery]'s [MediaQueryData.viewInsets] `bottom` property.
///
/// For example, if there is an onscreen keyboard displayed above the
/// scaffold, the body can be resized to avoid overlapping the keyboard, which
/// prevents widgets inside the body from being obscured by the keyboard.
///
/// Defaults to true.
final bool resizeToAvoidBottomInset;
If you put that to false, the body won't be resized so the content won't be overflowed.
If you leave it as default, you need to make the body scrollable. In your case, you could change the root Column for a ListView and you will need to remove the Expanded wrap of the third item of the column.
But I recommend you to try to simplify the structure of the widgets.
Wrap your widget with a SingleChildScroll widget and that should work and solve the overflow issue