SetState isnt defined in StatefulWidgt - android

Am trying to change the color of my container using the setState Method in onPress
but the app crashes with an error of setState isnt defined.And i want to ask for help.Any help provider will be appreciated.Thank you
import 'package:flutter/material.dart';
import 'AllContainers.dart';
import 'ColumnContainer.dart';
import 'AllConstants.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
enum AgeStatus { child, old }
class MyHomePage extends StatefulWidget {
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
AgeStatus? ageStatus;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Practising_Cards'),
),
body: Column(
children: <Widget>[
Expanded(
child: Row(
children: [
Expanded(
child: AllContainers(
onPress: () {
setState(() {
ageStatus = AgeStatus.child;
});
},
colors: ageStatus == AgeStatus.child
? activeColor
: deactiveColor,
mycard: MyColumnItems(FontAwesomeIcons.mars, 'FEMALE'),
),
),
Expanded(
child: AllContainers(
colors: ageStatus == deactiveColor
? activeColor
: deactiveColor,
onPress: () {
setState(() {
ageStatus = AgeStatus.old;
});
},
mycard: MyColumnItems(FontAwesomeIcons.mars, 'FEMALE'),
),
)
],
),
),
Container(
margin: EdgeInsets.only(top: 5),
width: double.infinity,
height: 50,
color: Colors.red,
),
],
),
);
}
}
this is the Container class
import 'package:flutter/material.dart';
import 'NewMain.dart';
class AllContainers extends StatelessWidget {
final Color colors;
final Widget mycard;
final Function onPress;
AllContainers(
{required this.colors, required this.mycard, required this.onPress});
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress(),
child: Container(
child: mycard,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: colors,
borderRadius: BorderRadius.circular(20),
),
),
);
}
}
I tried creating a function with the setState in it in the State and passed the function to my onPress method and that also didnt work.

AllContainers' property onTap has type Function.
But I think your intention is VoidCallback type.
So, you have to change the type of onTap property from Function to VoidCallback
And you have to pass not onPress() but onPress.
class AllContainers extends StatelessWidget {
final Color colors;
final Widget mycard;
// final Function onPress;
final VoidCallback onPress;
AllContainers({
required this.colors,
required this.mycard,
required this.onPress,
});
Widget build(BuildContext context) {
return GestureDetector(
// onTap: onPress(),
onTap: onPress,
child: Container(
child: mycard,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: colors,
borderRadius: BorderRadius.circular(20),
),
),
);
}
}

You should use final VoidCallback onPress inside your AllContainers instead of final Function onPress
this is the class you should use to solve your problem.
class AllContainers extends StatelessWidget {
final Color colors;
final Widget myCard;
final VoidCallback onPress;
const AllContainers(
{super.key,
required this.colors,
required this.myCard,
required this.onPress});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: colors,
borderRadius: BorderRadius.circular(20),
),
child: myCard,
),
);
}
}
please note that to use annotations and use camelCase in your coding.
happy coding...

Related

How to rebuild flutter Widget on Singleton value change

I am trying to rebuild a stateful widget every time a value in my global Singelton is changed but I'm stumped.
My goal is to rebuild my Cart Icon every time the cartSize is changed throughout my app.
I know I need to send out a notification whenever the Singelton cartSize value is changed. and listen for that notification in my stateful widget but how do I do this?
Any help is greatly appreciated.
My Global Singelton
library #######.globals;
import 'package:flutter/material.dart';
class GlobalSingleton extends ChangeNotifier {
static final GlobalSingleton _instance = GlobalSingleton._internal();
// passes the instantiation to the _instance object
factory GlobalSingleton() {
return _instance;
}
//initialize variables in here
GlobalSingleton._internal() {
cartSize = 0;
}
late int cartSize;
}
My stateful Widget
import 'package:######/globals/globals.dart';
import 'package:flutter/material.dart';
class BuildMarketplaceCartIcon extends StatefulWidget {
const BuildMarketplaceCartIcon({Key? key}) : super(key: key);
#override
State<BuildMarketplaceCartIcon> createState() =>
_BuildMarketplaceCartIconState();
}
class _BuildMarketplaceCartIconState extends State<BuildMarketplaceCartIcon> {
CRUDMarketplaceCart localCartData = CRUDMarketplaceCart();
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
},
child: Container(
width: 72,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Stack(
alignment: Alignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Icon(Icons.shopping_cart),
Text(
'Cart',
overflow: TextOverflow.ellipsis,
),
],
),
Positioned(
top: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
alignment: Alignment.center,
child: Text(
'${globals.GlobalSingleton().cartSize}',
),
),
),
],
),
),
);
}
}
When using ChangeNotifier you need to call notifyListeners when the value changes. You also need to have your widget listen to the ChangeNotifier, so that it knows when to rebuild.
The most common way to go about that is to use the provider package, which includes the ChangeNotifierProvider widget.
Using provider, your code would look something like this:
class GlobalSingleton extends ChangeNotifier {
static final GlobalSingleton _instance = GlobalSingleton._internal();
// passes the instantiation to the _instance object
factory GlobalSingleton() {
return _instance;
}
//initialize variables in here
GlobalSingleton._internal() {
_cartSize = 0;
}
late int _cartSize;
int get cartSize => _cartSize;
void set cartSize(int newCartSize) {
_cartSize = newCartSize;
notifyListeners();
}
}
Here, we update your singleton so that it will call notifyListeners() whenever the cartSize is set.
Next you'll need to update your widget to listen to the changes:
import 'package:######/globals/globals.dart';
import 'package:flutter/material.dart';
class BuildMarketplaceCartIcon extends StatefulWidget {
const BuildMarketplaceCartIcon({Key? key}) : super(key: key);
#override
State<BuildMarketplaceCartIcon> createState() =>
_BuildMarketplaceCartIconState();
}
class _BuildMarketplaceCartIconState extends State<BuildMarketplaceCartIcon> {
CRUDMarketplaceCart localCartData = CRUDMarketplaceCart();
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Container(
width: 72,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Stack(
alignment: Alignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Icon(Icons.shopping_cart),
Text(
'Cart',
overflow: TextOverflow.ellipsis,
),
],
),
Positioned(
top: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
alignment: Alignment.center,
child: ChangeNotifierProvider.value(
value: GlobalSingleton(),
child: Consumer<GlobalSingleton>(
builder: (context, singleton, child) {
return Text(
'${singleton.cartSize}',
);
},
),
),
),
),
],
),
),
);
}
}
Here I put the Provider widget as directly enclosing the Consumer widget - however, if you need the singleton's value in more than one place, you can put the Provider higher up the widget tree so that it's a common ancestor of any Consumer that listens to changes in the singleton.

Encaplsulating a widget for use in another dart file

What I'm trying to achieve:
Have a BottomNavigationBar widget in its own class in its own dart file called navigationBar.dart
Have a main.dart file that has a Scaffold widget that calls this class to create the BottomNavigationBar widget
Then in the main.dart file I want to be able to set the BottomNavigationBar from navigationBar.dart and I want to be able to change the body of the Scaffold widget in the main.dart file depending on which index is selected in the BottomNavigationBar widget (check the comment in the main.dart file in the body property for a better explanation)
Here is my code below so far:
navigationBar.dart
import 'package:flutter/material.dart';
import '../home.dart';
class NavigationBar extends StatefulWidget {
const NavigationBar({Key? key}) : super(key: key);
#override
State<NavigationBar> createState() => _NavigationBar();
}
class _NavigationBar extends State<NavigationBar> {
int selectedIndex = 2;
void _onItemTapped(int index) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.red,
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
backgroundColor: Colors.green,
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
backgroundColor: Colors.purple,
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
backgroundColor: Colors.pink,
),
],
currentIndex: selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
);
}
main.dart
import 'package:flutter/material.dart';
import 'components/navigationBar.dart';
void main() {
runApp(const MaterialApp(home: App()));
}
class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
#override
State<App> createState() => _App();
}
class _App extends State<App> {
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
),
Text(
'Index 1: Business',
),
Text(
'Index 2: School',
),
Text(
'Index 3: Settings',
),
];
#override
Widget build(BuildContext context) {
const navBar = navigationBar()
return Scaffold(
appBar: AppBar(
title: const Text('Test App',
style: TextStyle(
color: Colors.white,
fontFamily: 'LogoFont',
fontSize: 30.0,
letterSpacing: 1.5)),
centerTitle: true,
backgroundColor: Colors.lightBlue[500],
elevation: 0.0,
),
backgroundColor: Colors.lightBlue[800],
body: //something like this: _widgetOptions.elementAt(navbar.selectedIndex)
),
bottomNavigationBar: navBar);
}
}
Any ideas on how I could create what I need in the bullet points? Any help would be great, thanks
I think there is no way with stateful widget but you can do this by provider, like example below.
Provider:
class MainViewProvider with ChangeNotifier ,
DiagnosticableTreeMixin{
int activeItem = 2;
changeActiveItem(int activeElement){
activeItem = activeElement;
notifyListeners();
}
}
BottomNavBar Widget:
class BotNavWidget extends StatelessWidget {
const BotNavWidget({Key? key}) : super(key: key);
get context => null;
#override
Widget build(BuildContext context) {
final watch = context.watch<ColorsProvider>();
return Container(
padding: EdgeInsets.symmetric(
horizontal: getWidth(16), vertical: getHeight(10)),
child: Container(
height: SizeConfig.height! * .1,
width: SizeConfig.width!,
decoration: BoxDecoration(
color: watch.colors[1],
borderRadius: BorderRadius.circular(getWidth(20))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
buildIcon(watch.bottomIcons[0], context, 0),
buildIcon(watch.bottomIcons[1], context, 1),
buildIcon(watch.bottomIcons[2], context, 2),
buildIcon(watch.bottomIcons[3], context, 3),
buildIcon(watch.bottomIcons[4], context, 4),
],
),
),
);
}
buildIcon(ColorFiltered icon, BuildContext context, int i) {
final read = context.read<MainViewProvider>();
final watch = context.watch<MainViewProvider>();
final watchColors = context.watch<ColorsProvider>().colors;
return InkWell(
onTap: () async{
read.changeActiveItem(i);
},
child: Container(
padding: EdgeInsets.all(getWidth(15)),
height: SizeConfig.height! * .07,
width: SizeConfig.height! * .07,
decoration: BoxDecoration(
color: watch.activeItem == i ? watchColors[2] : Colors.transparent,
borderRadius: BorderRadius.circular(getWidth(20))),
child: SizedBox(
height: getHeight(24),
width: getHeight(24),
child: icon
),
),
);
}
}
P.S: You can use custom BottomNavigationBar Widget instead of making it manually

onPressed from MaterialButton were trigged when the page from initialRoute

There're two buttons from my WelcomeScreen, when this page is loaded, two buttons will be pressed automatically.
two buttons were used by the external widget"RoundButton".
Why I knew those buttons were being pressed, because I was using print function, and I saw the first button and second button were pressed automatically and sequentially.
Navigator.pushNamed(context, LoginScreen2.id);
Navigator.pushNamed(context, RegistrationScreen.id);
Navigator.pushNamed(context, LoginScreen2.id);
Navigator.pushNamed(context, RegistrationScreen.id);
Is there any setting I should set to prevent this problem? Thank you.
environment:
sdk: ">=2.16.0 <3.0.0"
build this program on Chroma
welcome_screen.dart
import 'package:trashcollectionday/Screens/login_screen2.dart';
import 'package:trashcollectionday/screens/registration_screen.dart';
import 'package:flutter/material.dart';
import 'package:trashcollectionday/screens/login_screen.dart';
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:trashcollectionday/components/roundedButton.dart';
class WelcomeScreen extends StatefulWidget {
static const String id = 'welcome_screen';
// will be a class, you don't have to to WelcomeScreen().index
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation animation;
late Animation animation1;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
children: <Widget>[
Hero(
tag: 'logo',
child: Container(
child: Image.asset('images/logo.png'),
height: 60,
),
),
DefaultTextStyle(
style: const TextStyle(
fontSize: 40.0,
fontFamily: 'Horizon',
),
child: AnimatedTextKit(
animatedTexts: [TypewriterAnimatedText('Application')],
),
),
],
),
const SizedBox(
height: 48.0,
),
RoundButton(
title: 'Log In',
colour: Colors.lightBlue,
onPressed: () {
print('Log In');
//Go to login screen.
Navigator.pushNamed(context, LoginScreen2.id);
},
),
RoundButton(
title: 'Register',
colour: Colors.blueAccent,
onPressed: () {
print('Reg');
//Go to login screen.
Navigator.pushNamed(context, RegistrationScreen.id);
},
),
],
),
),
);
}
}
roundedButton.dart
import 'package:flutter/material.dart';
class RoundButton extends StatelessWidget {
const RoundButton({required this.title, required this.colour, required this.onPressed});
final Color colour;
final String title;
final Function onPressed;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Material(
elevation: 5.0,
color: colour,
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
onPressed: onPressed(),
minWidth: 200.0,
height: 42.0,
child: Text(
title,
),
),
),
);
}
}
main. dart
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: Colors.teal,
textTheme: const TextTheme(bodyText2: TextStyle(color: Colors.yellow)),
primaryColor: Colors.orange,
),
initialRoute: WelcomeScreen.id,
// home: ItemDetailsScrrent(),
routes: {
WelcomeScreen.id : (context) => WelcomeScreen(),
LoginScreen2.id: (context) => LoginScreen2(),
RegistrationScreen.id: (context) => RegistrationScreen(),
RecordScreen.id: (context) => RecordScreen(),
LoginScreen.id: (context) => LoginScreen(),
ItemDetailsScrrent.id: (context) => ItemDetailsScrrent(),
},
// home: const LoginScreen(),
);
}
}
You should remove brackets from RoundButton class in
onPressed: onPressed()
to
onPressed:onPressed
and add brackets to this line of code
final Function onPressed;
as here
final Function() onPressed;
I'm not sure but maybe issue occurs because of you are using onPressed: onPressed() in RoundButton.
You can use this function without brackets like this; onPressed: onPressed,

on swipe how can i set text in text field after that edit text and insert again on that position where we swipe

on swipe how can I set text in the text field after that edit text and insert it again in that position. swipe in Dismissible and after swipe, I want my text on the input text field and change the text and add the text in the same position can you please help me strong text
enter image description here
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../models/model.dart';
import 'list_provider.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late GlobalKey<FormState> _formKey;
late TextEditingController _controller;
var taskItems;
int counter = 0;
late DynamicList listClass;
bool isUpdate =false;
#override
void initState() {[enter image description here][1]
// TODO: implement initState
super.initState();
_formKey = GlobalKey();
_controller = TextEditingController();
taskItems = Provider.of<ListProvider>(context, listen: false);
listClass = DynamicList(taskItems.list);
}
#override
void dispose() {
// TODO: implement dispose
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: TextFormField(
controller: _controller,
onSaved: (val) {
taskItems.addItem(val);
},
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState?.save();
_controller.clear();
}
},
child: Text('Add'),
),
),
const Padding(padding: EdgeInsets.all(8.0),
),
Consumer<ListProvider>(builder: (context, provider, listTile) {
return Expanded(
child: ListView.builder(
itemCount: listClass.list.length,
itemBuilder: buildList,
),
);
}),
],
),
**
-
> Heading
**
));
}
Widget buildList(BuildContext context, int index) {
counter++;
return Dismissible(
key: Key(counter.toString()),
direction: DismissDirection.startToEnd,
onDismissed: (direction) {
taskItems.deleteItem(index);
},
child: Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue,
width: 2,
),
borderRadius: BorderRadius.circular(10)),
child: ListTile(
title: Text(listClass.list[index].toString()),
trailing: IconButton(iconSize: 30, icon: Icon(Icons.delete),
onPressed: () {
setState(() {
taskItems.deleteItem(index);
},
);
},
),
),
),
);
}
}

onTap function as parameter is not working

I have created a custom button widget class with Icon and onTap constructors. I want to use this button in any screen with custom icon and custom function on button tapped.
class ActionButton extends StatelessWidget {
ActionButton({this.icon, this.onPress});
final FaIcon? icon;
final Function? onPress;
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(18.0),
// padding: const EdgeInsets.all(0.2),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(6.0)),
// padding: const EdgeInsets.all(1.0),
child: IconButton(
onPressed: () {
onPress!;
},
icon: icon!,
color: Colors.black,
),
);
}
}
As you can see, with this widget I can use this ActionButton in any screen with any icon and its action will be any function what I pass as argument.
But when I am using this button on my another page and passing function, function does not get executed:
class ProductDetailsScreen extends StatelessWidget {
final Product? product;
const ProductDetailsScreen({Key? key, this.product}) : super(key: key);
#override
Widget build(BuildContext context) {
Sizes(context).initSize();
final double _h = Sizes.screenHeight;
final double _w = Sizes.screenWidth;
final _theme = Theme.of(context);
final product = ModalRoute.of(context)!.settings.arguments as Product;
void _goBack() {
Navigator.of(context).pop();
print('the page is popped');
}
return Scaffold(
// backgroundColor: _theme.scaffoldBackgroundColor,
body: SafeArea(
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ActionButton(
icon: FaIcon(
Icons.arrow_back,
),
onPress: () {
_goBack();
}),
ActionButton(
icon: FaIcon(Icons.share),
)
],
),
ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
Container(
height: 60,
child: Image.asset('${product.imageSource}'),
)
],
)
],
),
),
);
}
}
that_ goBack() function is not working
please help me, thanks in advance
In Product Details page you need to pass the onPress parameter as follows:
ActionButton(icon:FaIcon(
Icons.arrow_back,
),onPress:_goBack)`
And in ActionButton class
IconButton( onPressed: () { onPress!(); }, icon: icon!, color: Colors.black, ),

Categories

Resources