How to enable buttons - flutter

In one of my Flutter app pages, I want to disable the next button at first. If the user enters any new value in the textfield, I want to enable next button. Here is my code, but the next button stays disabled no matter what. How can I enable the next button when a user enters a value?
#override
Widget build(BuildContext context) {
bool btnenabled = false;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
title: Text('Address'),
),
body: Column(
children: <Widget>[
.....
TextFormField(
onChanged: (newValue) {
_currentaddress = '$addressJSON' + newValue;
if (newValue.length > 0) {
setState(() {
btnenabled = true;
});
}
}),
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue[700], primary: Colors.white),
child: Text('next',
),
onPressed: btnenabled == true
? () => Navigator.push(context,
MaterialPageRoute(builder: (context) => Summary()))
: null)
],
),
);
}
}

You can copy paste run full code below
You can move bool btnenabled = false; out of Widget build
change from
Widget build(BuildContext context) {
bool btnenabled = false;
to
bool btnenabled = false;
...
Widget build(BuildContext context) {
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool btnenabled = false;
String _currentaddress = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
title: Text('Address'),
),
body: Column(
children: <Widget>[
TextFormField(onChanged: (newValue) {
_currentaddress = 'addressJSON' + newValue;
if (newValue.length > 0) {
setState(() {
btnenabled = true;
});
}
}),
TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue[700], primary: Colors.white),
child: Text(
'next',
),
onPressed: btnenabled == true
? () => Navigator.push(context,
MaterialPageRoute(builder: (context) => Summary()))
: null)
],
),
);
}
}
class Summary extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("Summary");
}
}

Related

Flutter - How to trigger an animation inside a child widget from its parent widget [duplicate]

Let said I have a widget "mySonWidget" inside this widget I have a function "updateIconColor", I want to call that function from the father of "mySonWidget"
I did something similiar with callback but this is not the same scenario.
I saw people other widgets doing similar thing with controllers, but I don't know how create a custom controller.
How can I do it?
HELP
class mySonWidget extends StatefulWidget {
#override
_mySonWidgetState createState() => _mySonWidgetState();
}
class _mySonWidgetState extends State<mySonWidget> {
var _iconColor = Colors.red[500];
void updateIconColor() {
setState(() {
print('updateIconColor was called');
_iconColor = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (Icon(Icons.star)),
color: _iconColor,
onPressed: () {},
),
);
}
}
father example:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(children: <Widget>[
mySonWidget(),
FlatButton(
onPressed: () {
/*..Call Function inside mySonWidget (updateIconColor) ..*/
},
child: Text(
"Change Color",
),
),
]),
),
);
}
}
You can copy paste run full code below
You can use GlobalKey can use _key.currentState to call updateIconColor()
code snippet
GlobalKey _key = GlobalKey();
...
mySonWidget(key: _key),
FlatButton(
onPressed: () {
final _mySonWidgetState _state = _key.currentState;
_state.updateIconColor();
},
...
class mySonWidget extends StatefulWidget {
mySonWidget({Key key}) : super(key: key);
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
GlobalKey _key = GlobalKey();
#override
Widget build(BuildContext context) {
return MaterialApp(
//theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
body: Column(children: <Widget>[
mySonWidget(key: _key),
FlatButton(
onPressed: () {
final _mySonWidgetState _state = _key.currentState;
_state.updateIconColor();
},
child: Text(
"Change Color",
),
),
]),
),
),
);
}
}
class mySonWidget extends StatefulWidget {
mySonWidget({Key key}) : super(key: key);
#override
_mySonWidgetState createState() => _mySonWidgetState();
}
class _mySonWidgetState extends State<mySonWidget> {
var _iconColor = Colors.red[500];
void updateIconColor() {
setState(() {
print('updateIconColor was called');
_iconColor = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (Icon(Icons.star)),
color: _iconColor,
onPressed: () {},
),
);
}
}

Flutter Switch will not work inside AlertBox

I am having a problem where when I try to use a switch widget it will not work properly inside of an alert box as in it does not switch over to the second state it just bounces whenever I try to flick it. I am wondering if this is because there is a problem with the switch itself or how I displayed it in the box? Thanks!
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
home: SwitchDemo(),
);
}
}
class SwitchDemo extends StatefulWidget {
const SwitchDemo({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() => new _TabsPageState();
}
class _TabsPageState extends State<SwitchDemo> {
bool isInstructionView;
#override
void initState() {
super.initState();
isInstructionView = Global.shared.isInstructionView;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("add data"),
),
body: Container(
child: TextButton(
child: Text('Open Alert Box'),
onPressed: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 20,
vertical:
MediaQuery.of(context).size.height / 20,
),
child: AlertDialog(
content: Container(
child: Switch(
value: isInstructionView,
onChanged: (bool isOn) {
if (isInstructionView == false) {
} else if (isInstructionView == true) {}
setState(() {
isInstructionView = isOn;
Global.shared.isInstructionView = isOn;
isOn = !isOn;
});
},
activeColor: Colors.blue,
inactiveTrackColor: Colors.grey,
inactiveThumbColor: Colors.grey,
),
),
),
);
})
}),
));
}
}
class Global {
static final shared = Global();
bool isInstructionView = false;
}
Wrap you AlertDialog with StatefulBuilder.
here is full code:
import 'package:flutter/material.dart';
class SwitchDemo extends StatefulWidget {
const SwitchDemo({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => new _TabsPageState();
}
class _TabsPageState extends State<SwitchDemo> {
late bool isInstructionView;
#override
void initState() {
super.initState();
isInstructionView = Global.shared.isInstructionView;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("add data"),
),
body: Container(
child: TextButton(
child: Text('Open Alert Box'),
onPressed: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 20,
vertical: MediaQuery.of(context).size.height / 20,
),
child: StatefulBuilder(builder: (context, setState) {
return AlertDialog(
content: Container(
child: Switch(
value: isInstructionView,
onChanged: (bool isOn) {
print(isInstructionView);
setState(() {
isInstructionView = !isInstructionView;
});
},
activeColor: Colors.blue,
inactiveTrackColor: Colors.grey,
inactiveThumbColor: Colors.grey,
),
),
);
}),
);
},
)
}),
));
}
}
class Global {
static final shared = Global();
bool isInstructionView = false;
}
Does it answer your question?
ref: https://stackoverflow.com/a/57240941/10157127

How to dynamically generate widgets in Flutter?

I have a dummy list of data. I want each item on the list to show a different widget when it is tapped, similar to a contacts app. Defining the widget in the onPressed method always returns the same widget. How can I generate each widget without manually creating each one?
void az() {
int c = "A".codeUnitAt(0);
int end = "Z".codeUnitAt(0);
while (c <= end) {
items.add(FlatButton.icon(
icon: Icon(Icons.image_aspect_ratio),
label: Text(
String.fromCharCode(c),
style: TextStyle(fontSize: 20),
),
onPressed: (){
print(String.fromCharCode(c)); //This should return a different widget
},
));
c++;
}
}
You can copy paste run full code below
You can declare a local variable start in for loop
code snippet
void az() {
int c = "A".codeUnitAt(0);
int end = "Z".codeUnitAt(0);
for (int start = c; start <= end; start++) {
items.add(FlatButton.icon(
icon: Icon(Icons.image_aspect_ratio),
label: Text(
String.fromCharCode(start),
style: TextStyle(fontSize: 20),
),
onPressed: () {
print(String.fromCharCode(
start)); //This should return a different widget
},
));
}
}
output
I/flutter (12880): A
I/flutter (12880): B
I/flutter (12880): C
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<Widget> items = [];
void az() {
int c = "A".codeUnitAt(0);
int end = "Z".codeUnitAt(0);
for (int start = c; start <= end; start++) {
items.add(FlatButton.icon(
icon: Icon(Icons.image_aspect_ratio),
label: Text(
String.fromCharCode(start),
style: TextStyle(fontSize: 20),
),
onPressed: () {
print(String.fromCharCode(
start)); //This should return a different widget
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
SecondRoute(yourParameter: String.fromCharCode(start))));
},
));
}
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
az();
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: items,
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class SecondRoute extends StatelessWidget {
final String yourParameter;
const SecondRoute({Key key, this.yourParameter}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('$yourParameter'),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}

How I can view FloatingActionButton on condition

I have list of orders orderList. If that isEmpty, FloatingActionButton is hide. In case orderList have products - FAB will be shown. My code:
bool statusFAB = false;
_getFABState(){
setState(() {
if(!orderList.isEmpty){
statusFAB = true;
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: _getFAB(),
backgroundColor: _kAppBackgroundColor,
body: Builder(
builder: _buildBody,
),
);
Widget _getFAB() {
if(statusFAB){
return FloatingActionButton(
backgroundColor: Colors.deepOrange[800],
child: Icon(Icons.add_shopping_cart),
onPressed: null);
}
}
It's not working, because condition work once, but state of orderList can be change anytime.
You don't need to store the statusFAB variable, you can just evaluate it on the fly. See updated sample below:
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: _getFAB(),
backgroundColor: _kAppBackgroundColor,
body: Builder(
builder: _buildBody,
),
);
Widget _getFAB() {
if (orderList.isEmpty) {
return Container();
} else {
return FloatingActionButton(
backgroundColor: Colors.deepOrange[800],
child: Icon(Icons.add_shopping_cart),
onPressed: null);
}
}
Well there is a shortcut which can be used with the ternary operator and can be used within Scaffold of a Stateful Widget as
floatingActionButton: orderList.isEmpty ? Container() : FloatingActionButton(...)
Unless you need a long and complicated function, this works fine. Even if you need a complicated function, then that function can be called only when the drawing was needed
floatingActionButton: orderList.isEmpty ? Container() : ComplicatedFn(...)
Widget ComplicatedFn() {
//.... Complicated Algo
return FloatingActionButton(...)
}
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Product> orderList = List();
int counter = 0;
void getCount(){
setState(() {
counter = orderList.length;
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Center(
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
onPressed: (){
if(orderList.isNotEmpty)
orderList.removeLast();
getCount();
},
icon: Icon(Icons.remove),
color: Colors.red,
),
Text('$counter'),
IconButton(
onPressed: (){
orderList.add(Product('product'));
getCount();
print('product added');
},
icon: Icon(Icons.add),
color: Colors.blue,
)
],
),
),
),
floatingActionButton: _getFAB()
);
}
Widget _getFAB() {
if (orderList.isEmpty) {
return Container();
} else {
return FloatingActionButton(
backgroundColor: Colors.deepOrange[800],
child: Icon(Icons.shopping_cart),
onPressed: null);
} }
}
class Product {
String title;
Product(this.title);
}

Flutter Inherited Widget - Missing some listener

I'm trying to get the following to work. Changes to the app model state are not picked up via the InheritedWidget 'AppStateProvider'. I've manage to get this working with sinks/streams but was hoping to established a simpler structure.
This is just a test application to switch between various app modes.
What's missing?
import 'package:flutter/material.dart';
void main() {
runApp(AppStateProvider(
child: RootPage(),
appState: new AppState(),
));
}
enum AppMode { introduction, login, home }
class AppState {
AppMode appMode;
AppState({
this.appMode = AppMode.introduction,
});
}
class AppStateProvider extends InheritedWidget {
final AppState appState;
AppStateProvider({Key key, Widget child, this.appState})
: super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AppStateProvider of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(AppStateProvider)
as AppStateProvider);
}
}
class RootPage extends StatelessWidget {
AppMode _mode;
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Inherited Widget Test',
theme: new ThemeData(
primarySwatch: Colors.blueGrey,
),
home: _body(context),
);
}
Widget _body(BuildContext context) {
final provider = AppStateProvider.of(context); //Registers as a listener
final state = provider.appState;
_mode = state.appMode;
return new Stack(
children: <Widget>[
new Offstage(
offstage: _mode != AppMode.introduction,
child: new MaterialApp(
home: ColorsListPage(
color: Colors.red,
targetAppMode: AppMode.login,
title: "Intro",
),
),
),
new Offstage(
offstage: _mode != AppMode.login,
child: new MaterialApp(
home: ColorsListPage(
color: Colors.blue,
targetAppMode: AppMode.home,
title: "Login",
),
),
),
new Offstage(
offstage: _mode != AppMode.home,
child: new MaterialApp(
home: ColorsListPage(
color: Colors.green,
targetAppMode: AppMode.introduction,
title: "Home",
),
),
),
],
);
}
}
class ColorDetailPage extends StatefulWidget {
final String title;
final MaterialColor color;
final int materialIndex;
final AppMode targetAppMode;
ColorDetailPage(
{this.color, this.title, this.targetAppMode, this.materialIndex: 500});
#override
_ColorDetailPageState createState() => new _ColorDetailPageState();
}
class _ColorDetailPageState extends State<ColorDetailPage> {
#override
Widget build(BuildContext context) {
final provider = AppStateProvider.of(context);
return Scaffold(
appBar: AppBar(
backgroundColor: widget.color,
title: Text(
'$widget.title[$widget.materialIndex]',
),
),
body: Container(
color: widget.color[widget.materialIndex],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
provider.appState.appMode = widget.targetAppMode;
});
},
heroTag: null,
),
);
}
}
class ColorsListPage extends StatefulWidget {
final MaterialColor color;
final String title;
final ValueChanged<int> onPush;
final AppMode targetAppMode;
final List<int> materialIndices = [
100,
200,
300,
400,
500,
600,
700,
800,
900,
];
ColorsListPage({this.color, this.targetAppMode, this.title, this.onPush});
#override
_ColorsListPageState createState() => new _ColorsListPageState();
}
class _ColorsListPageState extends State<ColorsListPage> {
#override
Widget build(BuildContext context) {
final provider = AppStateProvider.of(context);
return new Scaffold(
appBar: AppBar(
title: Text(widget.title),
backgroundColor: widget.color,
),
body: Container(
color: Colors.white,
child: _buildList(context),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
provider.appState.appMode = widget.targetAppMode;
});
},
heroTag: null,
));
}
Widget _buildList(BuildContext context) {
return ListView.builder(
itemCount: widget.materialIndices.length,
itemBuilder: (BuildContext content, int index) {
int materialIndex = widget.materialIndices[index];
return Container(
color: widget.color[materialIndex],
child: ListTile(
title: Text(
"$materialIndex",
style: TextStyle(fontSize: 24.0),
),
trailing: Icon(Icons.chevron_right),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ColorDetailPage(
color: widget.color,
title: widget.title,
targetAppMode: widget.targetAppMode,
materialIndex: materialIndex,
)),
);
}
//onTap: () => onPush(materialIndex),
));
},
);
}
}
You need to wrap your InheritedWidget inside a StatefulWidget
class _AppStateProvider extends InheritedWidget {
final AppStateProviderState data;
_AppStateProvider({Key key, #required Widget child, #required this.data})
: super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
}
class AppStateProvider extends StatefulWidget {
final Widget child;
final AppState appState;
AppStateProvider({
#required this.child,
#required this.appState,
});
static AppStateProviderState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_AppStateProvider)
as _AppStateProvider)
.data;
}
#override
AppStateProviderState createState() => AppStateProviderState(
appState,
);
}
class AppStateProviderState extends State<AppStateProvider> {
AppState appState;
AppStateProviderState(this.appState);
void updateAppMode(AppMode appMode) {
setState(() {
appState.appMode = appMode;
});
}
#override
Widget build(BuildContext context) {
return _AppStateProvider(
data: this,
child: widget.child,
);
}
}
for more information
pay attention to this method:
void updateAppMode(AppMode appMode) {
setState(() {
appState.appMode = appMode;
});
}
you can use it like this:
floatingActionButton: FloatingActionButton(
onPressed: () {
provider.updateAppMode(widget.targetAppMode);
},
heroTag: null,
),