I have a Widget to create a sidebar menu:
Widget dashboard(context) {
return Material(
elevation: 8,
color: backgroundColor,
child: Container(
padding: const EdgeInsets.only(left: 16, right: 16, top: 48),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
InkWell(child: Icon(Icons.menu, color: Colors.white), onTap: () {
setState(() {
isCollapsed = !isCollapsed;
});
},),
Text("Corona App", style: TextStyle(fontSize: 24.0, color: Colors.white)),
Icon(Icons.settings, color: Colors.white),
])
],
),
)
);
}
But I keep getting the error that my setState function isn't defined. My main app is a statefullwidget so this is pretty weird. Can anyone help me?
Here is the full code!
import 'package:flutter/material.dart';
final Color backgroundColor = Color(0xFF4A4A58);
class MenuDashboard extends StatefulWidget {
#override
_MenuDashboardState createState() => _MenuDashboardState();
}
class _MenuDashboardState extends State<MenuDashboard> {
bool isCollapsed = true;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: backgroundColor,
body: Stack(
children: <Widget>[
menu(context),
dashboard(context),
],
),
);
}
}
Widget menu(context) {
return Padding(
padding: const EdgeInsets.only(left: 16.0),
child: Align(
alignment: Alignment.centerLeft,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Home", style: TextStyle(color: Colors.white, fontSize: 20),),
SizedBox(height: 10.0),
Text("Brochures", style: TextStyle(color: Colors.white, fontSize: 20),),
SizedBox(height: 10.0),
Text("Visitekaartje", style: TextStyle(color: Colors.white, fontSize: 20),),
SizedBox(height: 10.0),
]
)
)
);
}
Widget dashboard(context) {
return Material(
elevation: 8,
color: backgroundColor,
child: Container(
padding: const EdgeInsets.only(left: 16, right: 16, top: 48),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
InkWell(child: Icon(Icons.menu, color: Colors.white), onTap: () {
setState(() {
isCollapsed = !isCollapsed;
});
},),
Text("Corona App", style: TextStyle(fontSize: 24.0, color: Colors.white)),
Icon(Icons.settings, color: Colors.white),
])
],
),
)
);
}
with the error message: 'The function setState isn't defined'
setState is a member of State class, which means it can only be called inside a class that extends a State class of a StatefulWidget. If your class is extending StatelessWidget, you can't called state members/methods provided by the super class, including setState, initState and dispose methods.
For the answer, you can't call setState outside of the State class, if possible, put the widget methods inside the class, or pass setState function as a parameter to those methods.
setState can only called inside StatefulWidget. So if I got it right, you use setState in Widget dashboard or menu widgets. It can't work, because those widgets in outside of class. Try to put widgets inside the class
Related
I want to print first element in the list "first ques"
but I'm getting different sort of errors tried using final also, then all sort of errors.
class _QuizPageState extends State<QuizPage> {
List<Widget> scoreKeeper = [];
List<String> questions = ["First ques", "seacond ques", "third ques"];
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Text(
"example text"
questions[0], //why its not displaying "first ques"
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
),
),
),
),
),
try this
class _QuizPageState extends State<QuizPage> {
List<Widget> scoreKeeper = [];
List<String> questions = ["First ques", "seacond ques", "third ques"];
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Text(
questions[0], //why its not displaying "first ques"
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
),
),
),
),
),
the reason you are getting error is that the Text widget takes only one string and you are passing two string to it.
First, you should remove const from the Expanded widget because you're using a variable inside on Text which is questions[0].
And I want to mention that its better to use questions.first for readability proposes and check if the list is empty before it to prevent possible errors.
So Here's the final result:
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
flex: 5,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Center(
child: Text(
questions.first,
//why its not displaying "first ques"
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 25.0,
color: Colors.white,
),
),
),
),
),
],
),
i'm very new to Flutter.
I have a stateful widget. Every time i click a counter, the whole build function runs and the results are updated.
But is there a way to make it a stateless widget and update only the relevant part somehow so i could avoid rebuilding the screen?
I have a stateful widget. Every time i click a counter, the whole build function runs and the results are updated.
But is there a way to make it a stateless widget and update only the relevant part somehow so i could avoid rebuilding the screen?
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home:Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State {
int long = 0;
void increaseCounter(){
setState(() {
long++;
});
}
void decreaseCounter(){
if(long > 0) {
setState(() {
long--;
});
}
}
Text numberOfDeliveries(){
return Text(
'$long deliveries today',
style: TextStyle(
color:Colors.white,
fontSize: 24.0,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text('Deliveries'),
backgroundColor: Colors.green,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Container(
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child:Padding(
padding: const EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
child: Text(
'Long',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 32.0,
color: Colors.white,
),
),
),
),
Expanded(
child:
// is it possible to update this without running the whole build again?
numberOfDeliveries(),
),
Expanded(
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
color:Colors.blue[100],
child: FlatButton(
onPressed: (){
decreaseCounter();
},
child: Text('-'),
),
),
),
Expanded(
child: Container(
padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
color:Colors.blue[500],
),
),
Expanded(
child: Container(
padding: EdgeInsets.symmetric(vertical: 32.0, horizontal: 0.0),
color:Colors.blue[900],
child: FlatButton(
onPressed: (){
increaseCounter();
},
child: Text('+'),
),
),
),
],
),
),
],
),
),
),
Expanded(
child: Container(
color: Colors.blue[800],
child: Row(
children: [
Text('Bottom'),
],
),
),
),
],
),
);
}
}
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
I am creating the tutorial screen in which the two views like:- one is should be in the center of the screen and another should at the bottom of the screen.
But my both view is not proper, please check the below images.
I have done some lines of the code to do it but the not getting the proper solution, please check below code once
import 'package:flutter/material.dart';
import 'package:page_indicator/page_indicator.dart';
import 'login_screen.dart';
class Tutorial extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _TutorialScreen();
}
}
class _TutorialScreen extends State<Tutorial> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Align(
alignment: Alignment.center,
child:Column(
children: <Widget>[
Container(
height: 250.0,
margin: EdgeInsets.only(left: 10.0,top: 40.0,right: 10.0),
child: PageIndicatorContainer(
pageView: PageView(
children: <Widget>[
Container(
color: Colors.red,
),
Container(
color: Colors.yellow,
),
Container(
color: Colors.blueAccent,
)
],
),
length: 3,
align: IndicatorAlign.bottom,
indicatorSpace: 5.0,
padding: EdgeInsets.all(10.0),
),
),
Container(
height: 80.0,
color: Colors.purple,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: OutlineButton(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => LoginScreen()));
},
textColor: Colors.white,
child: Text(
"Login",
style: TextStyle(color: Colors.white),
),
),
),
Container(
margin: EdgeInsets.only(left: 10.0),
child: RaisedButton(
onPressed: () {},
color: Colors.black54,
child:
Text("SignUp", style: TextStyle(color: Colors.white)),
),
),
],
),
)
],
)
),
);
}
}
Please check above code once and let me know once.
Use this to get required view
Stack(children: <Widget>[
Align(alignment: Alignment.center,
child: Container(width: 100, height: 100, color: Colors.redAccent,),),
Align(alignment: Alignment.bottomCenter,
child: Container(height: 100, color: Colors.purpleAccent,),)
],)
Put the bottom Container inside Align widget and use alignment: Alignment.bottomCenter .:
Align(
alignment: Alignment.bottomCenter,
child: Container(
height: 80.0,
color: Colors.purple,
child: Row(
... .... ... // other code
Thanks #Zulfiqar But It is not necessary to put the whole view inside the Stack widget and use the Align property with it.
We can also use the Expanded or flexible widget to come out from the problem.
We can also use the MediaQuery for it like below
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:page_indicator/page_indicator.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Material(
child:Align(
alignment: Alignment.center,
child:Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height*0.90, /////HERE I USED MEDIAQUERY FOR IT
child: PageIndicatorContainer(
child: PageView(
children: <Widget>[
Container(
color: Colors.red,
),
Container(
color: Colors.yellow,
),
Container(
color: Colors.blueAccent,
)
],
),
length: 3,
align: IndicatorAlign.bottom,
indicatorSpace: 5.0,
padding: EdgeInsets.all(10.0),
),
),
Container(
height: MediaQuery.of(context).size.height*0.10, ////HERE I USED MEDIAQUERY FOR IT
color: Colors.purple,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: OutlineButton(
onPressed: () {
},
textColor: Colors.white,
child: Text(
"Login",
style: TextStyle(color: Colors.white),
),
),
),
Container(
margin: EdgeInsets.only(left: 10.0),
child: RaisedButton(
onPressed: () {},
color: Colors.black54,
child:
Text("SignUp", style: TextStyle(color: Colors.white)),
),
),
],
),
)
],
)
),
);
}
}
And for the pageView i have used this library page_indicator: ^0.3.0
And output from above code is as follow
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.