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);
}
Related
So I followed a tutorial on how to implement a basic Flutter search bar with search Delegation. You can find the tutorial on this link: https://www.youtube.com/watch?v=FPcl1tu0gDs
class DataSearch extends SearchDelegate<String>{
final wordssuggest=["Word1","Word2"];
final recentwords=["Word1"];
#override
List<Widget> buildActions(BuildContext context){
return [
IconButton(onPressed: (){
query=" ";
}, icon: Icon(Icons.clear))
];
//actions for appbar
}
#override
Widget buildLeading(BuildContext context){
return IconButton(onPressed: (){
close(context, null);
}, icon: Icon(Icons.search));
//leasding icon on the left of the app bar
}
#override
Widget buildResults(BuildContext context){
//show some result
return Container(
color: Colors.grey,
height: 200,
width: 200,
child: Center(child: Text(query),)
);
}
#override
Widget buildSuggestions(BuildContext context){
//show suggestions
final suggestionList =query.isEmpty?
recentwords:wordssuggest.where((p)=>p.startsWith(query)).toList();
return ListView.builder(itemBuilder: (context, index)=>ListTile(
onTap:(){
showResults(context);
} ,
leading: Icon(Icons.work_rounded),
title: RichText(text: TextSpan(text: suggestionList[index].substring(0, query.length),
style: TextStyle(color:Colors.blue, fontWeight: FontWeight.bold),
children: [TextSpan(
text:suggestionList[index].substring(query.length),
style:TextStyle(color:Colors.grey)
)]),
)
),
itemCount: suggestionList.length,);
}
}
However, what is not working for me:
For SearchDelegate method in the DataSearch class:
'Methods must have an explicit list of parameters.Try adding a parameter list.dart(missing_method_parameters)'
For buildActions, buildLeading, builduggestions and buildResults Widgets:
'The declaration 'buildActions' isn't referenced.'
Inside buildSuggestions:
The method 'showResults' isn't defined for the type '_MainPageState'.
Inside buildLeading:
The method 'close' isn't defined for the type '_MainPageState'.
Please help
Maybe your problem is occur because of calling the search delegate class.
this code solve your problem!
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: Secondpage(title: 'Flutter Demo Home Page'),
);
}
}
class Secondpage extends StatelessWidget {
final String title;
Secondpage({required this.title});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
actions: [
IconButton(icon: Icon(Icons.add), onPressed: () async {
await showSearch<String>(
context: context,
delegate: DataSearch(),
);
},
)
],
));
}
}
Search Delegate
class DataSearch extends SearchDelegate<String>{
final wordSuggest=["Word1","Word2","Word3","Word4", "Word5","Word6", ];
final recentWords=["Word1"];
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = "";
// showSuggestions(context);
},
),
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
close(context, 'null');
},
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
);
}
#override
Widget buildResults(BuildContext context){
//show some result
return Container(
color: Colors.grey,
height: 200,
width: 200,
child: Center(child: Text(query),)
);
}
#override
Widget buildSuggestions(BuildContext context){
//show suggestions
final suggestionList =query.isEmpty?
recentWords:wordSuggest.where((p)=>p.startsWith(query)).toList();
return ListView.builder(itemBuilder: (context, index)=>ListTile(
onTap:(){
showResults(context);
} ,
leading: Icon(Icons.work_rounded),
title: RichText(text: TextSpan(text: suggestionList[index].substring(0, query.length),
style: TextStyle(color:Colors.blue, fontWeight: FontWeight.bold),
children: [TextSpan(
text:suggestionList[index].substring(query.length),
style:TextStyle(color:Colors.grey)
)]),
)
),
itemCount: suggestionList.length,);
}
}
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");
}
}
Having a problem with getting text to display in my home.dart file when it's entered in the FloatingActionButton.
Below is the code sample. Any suggestions where I am getting it wrong. I believe that the 'String value;' line must be within the same MaterialButton function, though not sure how to do it without ruining it further.
}`
I'm using a simple app here to demonstrade the behavior. You can test by copy and running this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SomeScreen(),
);
}
}
class SomeScreen extends StatefulWidget {
#override
_SomeScreenState createState() => _SomeScreenState();
}
class _SomeScreenState extends State<SomeScreen> {
String value = '';
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
await _createDialog(context);
setState(() {});
},
child: Icon(Icons.add),
backgroundColor: Colors.red,
),
body: Container(
color: Colors.blue,
child: Center(
child: Text(value),
),
),
);
}
_createDialog(context) async {
await showDialog(
context: context,
builder: (BuildContext dialogContext) {
return AlertDialog(
title: Text('title'),
content: TextField(
onChanged: (text) {
value = text;
},
),
actions: <Widget>[
FlatButton(
child: Text('buttonText'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
}
}
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
// There I want to change title, background color etc
},
),
title: Text('title'),
dense: false,
),
I want to change properties of list tile from its own onTap()
You can copy paste run full code below
You can use StatefulWidget and call setState inside onTap
code snippet
class _ListTileCustomState extends State<ListTileCustom> {
String _title = "title";
Color _color = Colors.blue;
#override
Widget build(BuildContext context) {
return ListTile(
tileColor: _color,
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState(() {
_title = "changed";
_color = Colors.red;
});
},
child: Icon(Icons.add)),
title: Text(_title),
dense: false,
);
}
}
working demo
full code
import 'package:flutter/material.dart';
class ListTileCustom extends StatefulWidget {
#override
_ListTileCustomState createState() => _ListTileCustomState();
}
class _ListTileCustomState extends State<ListTileCustom> {
String _title = "title";
Color _color = Colors.blue;
#override
Widget build(BuildContext context) {
return ListTile(
tileColor: _color,
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState(() {
_title = "changed";
_color = Colors.red;
});
},
child: Icon(Icons.add)),
title: Text(_title),
dense: false,
);
}
}
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;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListTileCustom(),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
you can define one variable before build a method and use that variable to the title of listtile and when you ontap then change the state using setState and It will change the title of your listtie.
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState((){
title="your text"
});
},
),
title: Text(title),
dense: false,
),
here title is variable
and ListTile also has property of onTap
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!'),
),
),
);
}
}