how to change properties of list tile from its onTap() function in flutter? - flutter

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

Related

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!'),
),
),
);
}
}

In flutter, can you set the appbar backgorund to change base on the value of a dropdown box?

my drop down box cycles through 5 strings
['blue','red','yellow','orange','grey']
I want my appbar title to be that dropdown box and for the value in the dropdown to determine the appbar color
DropDownWidget ddw = DropDownWidget();
var color = {
"blue": Colors.blue,
"red": Colors.red,
"yellow": Colors.yellow,
"orange": Colors.orange,
"grey": Colors.grey,
};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: ddw,
backgroundColor: color[ddw],
),
}
The dropdown (ddw) shows up as the title, no problem.
I made a dictionary with those strings as the keys and the corresponding color as the value, but I am not able to use the string value of the dropdown to change the background.
Any suggestions?
You can copy paste run full code below
You can call setState in onChanged of DropdownButton
code snippet
appBar: AppBar(
backgroundColor: _appbarColor,
...
DropdownButton<Item>(
hint: Text("Select item"),
value: selectedColor,
onChanged: (Item Value) {
setState(() {
selectedColor = Value;
_appbarColor = selectedColor.color;
});
},
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class Item {
const Item(this.name, this.color);
final String name;
final Color color;
}
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;
Color _appbarColor = Colors.blue;
Item selectedColor;
List<Item> colorList = <Item>[
const Item('blue', Colors.blue),
const Item('red', Colors.red),
const Item('yellow', Colors.yellow),
];
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: _appbarColor,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButton<Item>(
hint: Text("Select item"),
value: selectedColor,
onChanged: (Item Value) {
setState(() {
selectedColor = Value;
_appbarColor = selectedColor.color;
});
},
items: colorList.map((Item item) {
return DropdownMenuItem<Item>(
value: item,
child: Row(
children: <Widget>[
Container(
height: 15,
width: 15,
color: item.color,
),
SizedBox(
width: 10,
),
Text(
item.name,
style: TextStyle(color: Colors.black),
),
],
),
);
}).toList()),
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),
),
);
}
}

MaterialPageRoute goes to a new page without the appbar using it with bottomNavigationBar

I have an app with three routes and uses the bottomNavigationBar to navigate between them. In one of the routes I have a button in the page that will also navigate to one of the pages.
Heres my main page
import 'package:flutter/material.dart';
import 'page_two.dart';
import 'page_three.dart';
void main() {
return runApp(MyApp());
}
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
List<Widget> _widgetOptions = <Widget>[
Text('Main'),
PageTwo(),
PageThree(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home, color: Colors.black),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
Page Two
import 'package:flutter/material.dart';
import 'main.dart';
class PageTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
},
),
);
}
}
and Page Three with a button that navigates to page two
import 'package:flutter/material.dart';
import 'page_two.dart';
class PageThree extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageTwo()),
);
},
),
);
}
}
When I press the button on Page Three, it will go to Page Two without the AppBar and the BottomNavigationBar
Use GlobalKey and In PageTwo Widget call MyStatefulWidgetState's _onItemTapped function
You can see working demo and full code below
code snippet
final scakey = new GlobalKey<_MyStatefulWidgetState>();
...
child: Text('Go page 2'),
onPressed: () {
scakey.currentState._onItemTapped(1);
full code
import 'package:flutter/material.dart';
void main() {
return runApp(MyApp());
}
final scakey = new GlobalKey<_MyStatefulWidgetState>();
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(key: scakey),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
final myKey = new GlobalKey<_MyStatefulWidgetState>();
List<Widget> _widgetOptions = <Widget>[
Text('Main'),
PageTwo(),
PageThree(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: myKey,
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home, color: Colors.black),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
class PageTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
},
),
);
}
}
class PageThree extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 2'),
onPressed: () {
scakey.currentState._onItemTapped(1);
/*Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageTwo()),
);*/
},
),
);
}
}
When using navigation bar to navigate between pages, you are tapping on BottomNavigationBarItem to change the index by calling setState() and as the result, build method is triggered with a new _selectedIndex and that index is used to render your appropriate widget.
_widgetOptions.elementAt(_selectedIndex)
Navigator.push on the other hand is just pushing a new route on top of the navigation stack. You are not getting an AppBar or BottomNavigationBar since you don't have them on PageTwo. What I would recommend you is to create a callback function in PageTwo and call that function on button tap. You can now use that callback in MyStatefulWidget to change the index with setState. Here is an example
Declare a final like below in your pages.
final void Function(int index) pageChanged;
In the onTap event of your button, call this function.
widget.pageChanged(1); // PageTwo
In MyStatefulWidget, when you are creating pages, pass the function.
PageTwo(pageChanged:(index){
setState(){_selectedIndex = index;}
});

How do I access BuildContext outside of a stateful or stateless widget?

I created a class that extends the AppBar class in Flutter so I can reuse it whenever I need it.
My problem is how do I access the Stateful/Stateless widget build context?
class AppBarLayout extends AppBar {
static final AppController _appController = new AppController();
final GlobalKey<ScaffoldState> _scaffoldKey;
final String appBarTitle;
AppBarLayout(this.appBarTitle,this._scaffoldKey): super(
title: Text(appBarTitle),
leading: IconButton(
onPressed: () => _scaffoldKey.currentState.openDrawer(),
iconSize: 28,
icon: Icon(Icons.menu,color: Colors.white),
),
actions: <Widget>[
IconButton(
onPressed: () => _appController.signOut().then((_) {
_appController.navigateTo(context, new GoogleSignView());
}),
icon: Icon(Icons.account_box),
padding: EdgeInsets.all(0.0),
),
],
);
}
You would need to wrap your Scaffold in a Staless or Stateful widget, so you can get the context, e.g.
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> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarLayout(GlobalKey(debugLabel: 'someLabel'), appBarTitle: 'The Title', context: context,),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class AppBarLayout extends AppBar {
final GlobalKey<ScaffoldState> _scaffoldKey;
final String appBarTitle;
final BuildContext context;
AppBarLayout(this._scaffoldKey, {this.appBarTitle, this.context}): super(
title: Text(appBarTitle),
leading: IconButton(
onPressed: () => _scaffoldKey.currentState.openDrawer(),
iconSize: 28,
icon: Icon(Icons.menu,color: Colors.white),
),
actions: <Widget>[
IconButton(
onPressed: () {
print('Button pressed');
},
icon: Icon(Icons.account_box),
padding: EdgeInsets.all(0.0),
),
],
);
}
Here I'm using a very similar Widget of what you have.

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);
}