What is best way to remove overflowing by a lot of pixels in Flutter? - flutter

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

Related

How to avoid RenderFlow error when keyboard appears in Flutter

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.

Refresh ListView.builder On Button Click in Flutter

I am using the below code, where I have a ListView that had a switch.
I want to implement something like when I click on the RaisedButton - it will reload the ListView and all the values of switch.value should be changed to either true or false.
The user can either change the value of the switch from items in the ListView or from the button click.
I do not have an idea on how I should change the value or all the switches in the ListView.
return Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width / 2,
height: 100,
padding: EdgeInsets.all(20),
child: RaisedButton(
onPressed: () {
},
child: Text(
BTN_START_TRIP,
style: new TextStyle(
fontSize: 20.0,
),
),
textColor: buttonFontColor,
color: buttonColor,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(15.0))
),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(3.0),
// Let the ListView know how many items it needs to build.
itemCount: snapshot.data.results.length,
// Provide a builder function. This is where the magic happens.
// Convert each item into a widget based on the type of item it is.
itemBuilder: (context, index){
return Container(
height: 120,
child: Card(
elevation: 10,
child: InkWell(
splashColor: Colors.blue.withAlpha(30),
onTap: () {
print(snapshot.data.results[index].original_title);
},
child: Container(
height: 120,
child: Row(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 0, 5, 0),
width: MediaQuery.of(context).size.width -90,
child: Align(
alignment: Alignment.topLeft,
child: Text(snapshot.data.results[index].original_title,
textAlign: TextAlign.left,
style: TextStyle(fontSize: defaultTitleFontsize, color: defaultFontColor),
maxLines: 5),
),
),
Container(
padding: EdgeInsets.fromLTRB(20, 0, 5, 0),
child: Align(
alignment: Alignment.topLeft,
child: Text(snapshot.data.results[index].original_language,textAlign: TextAlign.left,style: TextStyle(fontSize: defaultsubTitleFontsize, color: defaultFontColor)),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
child: Switch(
value: false,
onChanged: (value){
setState(() {
print(value);
});
}
),
),
],
),
]
),
),
),
),
);
},
),
)
],
);
You'll need to have a variable to decide if the switch should be on or off. And during a certain event (click of button e.g) set the variable to appropriate value & re-trigger the build (re-painting of the UI) by calling setState. You'll need to have the above logic part of a stateful widget to accomplish that.

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

Flutter nested GestureDetector doesn't work

everyone! I have a list of items. The main Widget in the list is Card. I wanna wrap it in a GestureDetector to catch tap event on a whole card. I also have Stack inside the card where I have bookmark icon. I am trying to wrap this icon into GestureDetector but it doesn't work.
My item:
#override
Widget build(BuildContext context) {
// TODO: implement build
return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
ClickableIcon(_model._bookmarked),
Container(
height: 128.0,
constraints: BoxConstraints(minWidth: double.infinity),
child: Image.network(_model._headerSource),
),
],
),
Container(
height: 72,
constraints: BoxConstraints(minWidth: double.infinity),
child: Row(
children: <Widget>[
Container(
margin: const EdgeInsets.only(left: 16.0, right: 16.0),
child: CircleAvatar(
radius: 20.0,
backgroundImage: NetworkImage(_model._organizerLogo),
backgroundColor: Colors.transparent,
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_model._eventName,
style: TextStyle(
fontSize: 15,
color: Colors.black,
fontWeight: FontWeight.w500),
textAlign: TextAlign.start,
),
SizedBox(
height: 8,
),
Text(
"${_model._timeStart} ${_model._guide}",
style: TextStyle(
fontSize: 12,
color: Color(GoEngColors.secondaryTextColor),
fontWeight: FontWeight.w500),
)
])
],
),
)
],
),
);
}
Clickable icon code:
class _ClickableIconState extends State<ClickableIcon> {
#override
Widget build(BuildContext context) {
// TODO: implement build
return InkWell(
onTap: () {
print("bookmarked");
setState(() {
print("state updated");
widget.selected = !widget.selected;
});
},
child: Container(
child: Icon(widget.selected
? CustomIcon.MyFlutterApp.icon_mark_applouded_1
: CustomIcon.MyFlutterApp.icon_mark_empty_1),
alignment: Alignment.topRight,
),
);
}
}
I tried both GestureDetector and InkWell but none of them gave an expected result. I also tried to set a behaviour for a GestureDetector, but it didn't help as well.
So my question is as follows: how to make icon clickable remaining click implementation for the whole card? Thanks!
EDIT
Using IconButton instead of Icon didn't help.
I think your stack order need to be reversed
Stack(
children: <Widget>[
Container(
height: 128.0,
constraints: BoxConstraints(minWidth: double.infinity),
child: Image.network(_model._headerSource),
),
ClickableIcon(_model._bookmarked),
],
),
please, test and let me know if it worked for you.

How to put scroll view inside stack widget in flutter

I am making a flutter application in which i uses body as a stack and in this stack i have two child.One is main body and other is back button which is at top of screen.The first child of stack is scrollview.Here is my build method.
Widget build(BuildContext context) {
return Scaffold(
//debugShowCheckedModeBanner: false,
key: scaffoldKey,
backgroundColor: Color(0xFF5E68A6),
body: Stack(
children: <Widget>[
Container(
margin: const EdgeInsets.fromLTRB(0.0, 10.0 , 0.0 , 0.0 ),
height: double.infinity,
child:CustomScrollView(
slivers: <Widget>[
new Container(
margin: EdgeInsets.all(15.0),
child:Text(getTitle(),
style: TextStyle(fontSize: 20.0,fontWeight: FontWeight.bold,color: Colors.white),
),
),
//middle section
_isLoading == false ?
new Expanded(child: GridView.builder(
itemCount: sub_categories_list.length,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context, position){
return InkWell(
child: new Container(
//color: Colors.white,
padding: EdgeInsets.all(20),
margin: EdgeInsets.all(10),
height: 130,
width: 130,
child: new Center(
child :
Text(sub_categories_list[position].name,
style: TextStyle(fontSize: 18.0,fontWeight: FontWeight.bold),
)
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(16)),
// border: Border.all(color: Colors.black, width: 3),
),
),
onTap: () {
//write here
// Fluttertoast.showToast(msg: "You clicked id :"+sub_categories_list[position].cat_id.toString());
Navigator.pushNamed(context, '/advicemyself');
},
);
}
))
:
CircularProgressIndicator(),
Container(
margin: EdgeInsets.all(18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Column(
children: <Widget>[
Image.asset('assets/bt1.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("FIND HELP",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
new Column(
children: <Widget>[
Image.asset('assets/bt2.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("HOME",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
new Column(
mainAxisAlignment:MainAxisAlignment.spaceEvenly,
children: <Widget>[
Image.asset('assets/bt3.png'),
Container(
margin: EdgeInsets.all(10.0),
child: Text("CALL 999",
style: TextStyle(fontSize: 18.0,color: Colors.white),
),
)
],
),
],
),
),
],
),
),
Positioned(
left: 10,
top: 30,
child: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => {
//go back
},
color: Colors.white,
iconSize: 30,
),
),
// makeview()
],
),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
I have also tried using SingleChildScrollView but that also does not works.What i am doing wrong here ?
Here is link to the design which i want to make.
https://imgur.com/a/w7nLmKC
The back should be above scroll view so i used stack widget.
Running your sample code, there doesn't seem to be a need for overlapping widgets. Using Stack seems to be unnecessary. One way you could do is by using Column widget, and using Expanded as you see fit.
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Widget(), // back button goes here
CustomScrollView(...),
],
),
);
}
Otherwise, if you really need to use Stack, the scroll function should work fine. I've tried this locally and the Stack widget doesn't interfere with scrolling of Slivers, ListView, and GridView.
Stack(
children: [
/// Can be GridView, Slivers
ListView.builder(),
/// Back button
Container(),
],
),