One ListView isn't scrollable in AnimatedCrossFade - android

I'm new in flutter development and I have a problem:
I create new AnimatedCrossFade and add two different ListView to first and second child, but always one child ListView scrollable. How can I do scrollable ListView in first and second child?
(Same situation with simple GridView.)

This looks like a bug in AnimatedCrossFade. I filed an issue.
You can work around it by not using AnimatedCrossFade and building your own animation using FadeTransition. Source code is below. Click the play button, it will start like this
and end like this:
You can fade back and forth by clicking the button again. Both lists are scrollable and it remembers your scroll position.
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
createState() => new MyAppState();
}
class MyAppState extends State<MyApp> with TickerProviderStateMixin {
AnimationController _controller;
Key _key1 = new GlobalKey();
Key _key2 = new GlobalKey();
#override
void initState() {
_controller = new AnimationController(
duration: const Duration(milliseconds: 700),
vsync: this,
);
}
Widget _buildList(Key key, Color color, double opacity) {
return new Opacity(
opacity: opacity,
child: new Container(
// Keep the hidden ListView around to maintain its scroll position
// but set its height to 0.0 so it can't interfere with touches
height: opacity == 0.0 ? 0.0 : null,
decoration: new BoxDecoration(color: color),
child: new ListView(
key: new GlobalObjectKey(color),
children: new List.generate(
100,
(index) => new Text('Item $index'),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new Scaffold(
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.play_arrow),
onPressed: () {
if (_controller.status == AnimationStatus.dismissed ||
_controller.status == AnimationStatus.reverse) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
body: new Center(
child: new Container(
width: 100.0,
height: 100.0,
child: new AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return new Stack(
children: [
_buildList(_key1, Colors.red[200], _controller.value),
_buildList(_key2, Colors.blue[200], 1.0 - _controller.value),
],
);
}
),
),
),
),
);
}
}
}

Related

Change text color of a Text widget onTap

Im building a list from Firestore collection stream using ListViewBuilder, each item is a Text widget in the list, Im trying to change color of the text onTap the Text widget,
Item 1
Item 2
Item 3
when touching/onTap Item1, text color of Item1 should be changed
I implemented using GestureDetector with setState but on onTap>setState execution, the listview of the stream is rebuilt, giving a second of blank screen/flicker and loosing the actual state since its refreshed
var _dynamicTextColor = Colors.green;
return ListView.builder(
reverse: true,
itemCount: itemStream.length,
itemBuilder: (context, itemIndex) => Container(
child:GestureDetector(
onTap: (){
setState(() {
_dynamicTextColor = Colors.white;
});
},
child: Text(itemStream[itemIndex]['title'], style: TextStyle(color:_dynamicTextColor),),
),
),
);
You can try the following. This will use the selected property to decide which container should be blue.
class _TestState extends State<Test> {
String selected = "first";
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
selected = 'first';
});
},
child: Container(
height: 200,
width: 200,
color: selected == 'first' ? Colors.blue : Colors.transparent,
child: Text("First"),
),
),
GestureDetector(
onTap: () {
setState(() {
selected = 'second';
});
},
child: Container(
height: 200,
width: 200,
color: selected == 'second' ? Colors.blue : Colors.transparent,
child: Text("Second"),
),
),
],
);
}
}
I recommend you use a state management, for example Provider.
I prepared an example, I hope you understand it and solve your problem.
First, add the provider package to pubspec.yaml
provider: ^4.3.3
Then, create a class where you will manage the states, as you would with setState. The code would be like this:
class ColorProvider extends ChangeNotifier {
ColorProvider();
bool isPressed = true;
Color color = Colors.black;
changeColor() {
if (isPressed == true) {
color = Colors.green;
isPressed = false;
} else {
color = Colors.black;
isPressed = true;
}
notifyListeners();
return isPressed;
}
}
Once this is done, you must Wrap the App material in a ChangeNotifierProvider widget:
import 'package:flutter/material.dart';
import 'package:flutter_application_1/home_page.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ColorProvider(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(),
),
);
}
}
And finally, call the Provider in the widget:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
final providerWatch = context.watch<ColorProvider>();
final providerRead = context.read<ColorProvider>();
String text = 'This is an example text';
return Scaffold(
body: Container(
child: Center(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => providerRead.changeColor(),
child: Text(
text,
style: TextStyle(color: providerWatch.color),
)),
),
));
}
}
and this would be the result:

Create a card widget which will expand to a new screen when swiped up

I am learning flutter and I have come across this UI on dribble which I am trying to replicate for practice.
https://gph.is/g/4oLJ0k5
As you can see in the above gif, there is a card widget which expands to a new screen when you swipe up. And you can pop the screen by swiping down (or clicking on the back button). How do I implement this? I want it to look and feel exactly like shown in the gif.
I am pretty new to flutter so if you could provide a little more detail to your explanations it would be amazing.
Use container transform in animations.
https://pub.dev/packages/animations
hey I tried 2 animation but couldn't made exactly same.
I just used hero widget & ScaleTranstion widget
hope you like it.
see_video
CODE:
class AnimationDemo extends StatefulWidget {
#override
_AnimationDemoState createState() => _AnimationDemoState();
}
class _AnimationDemoState extends State<AnimationDemo> {
int changeIndex=0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Animation Demo"),
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
stops: [
0.1,
0.4,
],
colors: [
Colors.blue, // changeIndex.isEven? Colors.yellow:Colors.blue,
Colors.indigo,//changeIndex.isEven ?Colors.red:Colors.indigo,
])),
// color: Colors.white,
alignment: Alignment.center,
padding: const EdgeInsets.all(10),
child: new Center(
child: new Container(
alignment: Alignment.center,
height: 300.0,
child: new ListView(
scrollDirection: Axis.horizontal,
children: new List.generate(10, (int index) {
setState(() {
changeIndex = index;
});
print("index:$index");
return new InkWell(
child: Hero(
tag: index,
child: Card(
color: Colors.white,
child: new Container(
alignment: Alignment.center,
width: 300.0,
height: 300.0,
child: new Text("$index"),
),
),
),
onTap: (){
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return new SecondPage(index: index,);
}));
// Navigator.of(context).push(new SecondAnimationPage(index)); ANOTHER ANIMATION WITH SCALE TRANSITION WIDGET.
},
);
}),
),
),
),
)
);
}
}
class SecondPage extends StatelessWidget {
final int index ;
const SecondPage({Key key, this.index}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Hero Animations Example")),
body: Hero(
tag: index,
child: Container(
alignment: Alignment.center,
child: Card(
elevation: 5,
child: Text(index.toString()),
),
),
)
);
}
}
SECOND TRIED:
class SecondAnimationPage extends CupertinoPageRoute {
final int index;
SecondAnimationPage(this.index) : super(builder: (BuildContext context) => new ViewPage(index: index,));
#override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return new
ScaleTransition(
scale: animation,
child: new ViewPage(index: index,)
);
}
}
class ViewPage extends StatefulWidget {
final int index;
const ViewPage({Key key, this.index}) : super(key: key);
#override
_ViewPageState createState() => new _ViewPageState();
}
class _ViewPageState extends State<ViewPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Transition Animation'),
),
body: new Center(
child: new Text(widget.index.toString()),
),
);
}
}

How to adjust images size with respect to mobile size while using "CarouselSlider" and put button text on that image in flutter?

I'm trying to create intro walkthrough slider for my app but I am unable to do things right. Using carousel_slider provided by pub.dev. I am not able to fill image to entire mobile screen. It leave some empty space on both left and right side.
Using Carousel Pro I can't place button or text on the sliding images. I spend hours on some a small issue but wasn't able to achieve what I want.
Here is the code
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(), // Making initializing home sceen
));
}
List<String> imgList = [
"lib/assets/images/sunset.jpg",
"lib/assets/images/sample3.jpg",
"lib/assets/images/sample2.jpg",
"lib/assets/images/sunshine.jpg",
"lib/assets/images/leaf.png",
];
int current = 0;
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// var _userName = TextEditingController();
#override
Widget build(BuildContext context) {
Container(
child: ImageCarousel(),
);
}
class ImageCarousel extends StatefulWidget {
#override
_ImageCarouselState createState() => _ImageCarouselState();
}
class _ImageCarouselState extends State<ImageCarousel> {
#override
Widget build(BuildContext context) {
// >>>>>>>>>>>> C A R O U S E L S L I D E R C O D E
return CarouselSlider(
height: double.infinity,
initialPage: 0,
enableInfiniteScroll: false,
onPageChanged: (index) {
setState(() {
current = index;
});
},
items: imgList.map((imgUrl) {
return Builder(
builder: (BuildContext context) {
return Container(
//width: MediaQuery.of(context).size.width,
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 1),
decoration: BoxDecoration(
color: Colors.green,
),
child: Image(
image: AssetImage(
imgUrl,
),
fit: BoxFit.cover,
),
);
},
);
}).toList(),
);
}
}
Below are the screen shots for more clarification
Screenshot 1
Screenshot 2
Using Carousel_Pro provided by pub.dev, how can I put text or buttons over image.
class ImageCarousel extends StatefulWidget {
#override
_ImageCarouselState createState() => _ImageCarouselState();
}
class _ImageCarouselState extends State<ImageCarousel> {
#override
Widget build(BuildContext context) {
return Carousel(
images: [
AssetImage("lib/assets/images/sample2.jpg"),
AssetImage("lib/assets/images/sample3.jpg"),
]
);
Screenshot 3
Screenshot 4
Btw I have install all packages and images in pubspec.yaml.
For carousel_slider to fill whole page set: viewportFraction: 1.0
To put stuff on top of the image create stack:
CarouselSlider(
height: double.infinity,
viewportFraction: 1.0,
initialPage: 0,
enableInfiniteScroll: false,
items: imgList.map((imgUrl) {
return Stack(
children: <Widget>[
Image(
height: double.infinity,
image: NetworkImage(
imgUrl,
),
fit: BoxFit.cover,
),
Text("TEST")
],
);
}).toList(),
))

make clickable below page in stack flutter

I have just a stack that contains a guillotine menu and a list. But below page (list and fab) isn't clickable! First code is Main page, second code is books (below page) and third code is guillotine menu.
How can I make clickable below page?
main page
import 'package:firebase_example/Ui/Books.dart';
import 'package:firebase_example/Ui/GuillotineMenu.dart';
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final GlobalKey<ScaffoldState> _drawerKey = new GlobalKey();
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
top: false,
bottom: false,
child: new Container(
child: new Stack(
alignment: Alignment.topLeft,
children: <Widget>[
Books(),
GuillotineMenu(),
],
),
),
),
);
What you're looking for is IgnorePointer. By using it you should be able to exclude your widget from hit testing (and so allow things under it to be touched instead).
You're going to have to be careful about how you implement the button that makes the guillotine menu open/close though. I'd advise making it a part of the item lower in the stack, and then setting IgnorePointer's ignoring = true when the guillotine is closed.
Note that there might be a 'better' way of implementing the guillotine menu using PageRoutes. That way you'd just be pushing/popping a new route on top of the existing navigator rather than having to maintain your own stack.
Here's the code:
class GuillotinePageRoute<T> extends PageRoute<T> {
GuillotinePageRoute({
#required this.builder,
RouteSettings settings: const RouteSettings(),
this.maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
super(settings: settings, fullscreenDialog: fullscreenDialog);
final WidgetBuilder builder;
#override
final bool maintainState;
#override
Duration get transitionDuration => const Duration(milliseconds: 500);
#override
Color get barrierColor => null;
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final Widget result = builder(context);
assert(() {
if (result == null) {
throw new FlutterError('The builder for route "${settings.name}" returned null.\n'
'Route builders must never be null.');
}
return true;
}());
return result;
}
#override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
MediaQueryData queryData = MediaQuery.of(context);
var topInset = queryData.padding.top;
Offset origin = Offset((kToolbarHeight / 2.0), topInset + (kToolbarHeight / 2.0));
Curve curve = animation.status == AnimationStatus.forward ? Curves.bounceOut : Curves.bounceIn;
var rotateTween = new Tween(begin: -pi / 2.0, end: 0.0);
Cubic opacityCurve = Cubic(0.0, 1.0, 0.0, 1.0);
return new AnimatedBuilder(
animation: animation,
child: child,
builder: (context, child) {
return Opacity(
opacity: opacityCurve.transform(animation.value),
child: Transform(
transform: Matrix4.identity()..rotateZ(rotateTween.lerp(curve.transform(animation.value))),
origin: origin,
child: child,
),
);
},
);
}
#override
String get barrierLabel => null;
}
And using it in an example:
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MenuPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(children: [
AppBar(
leading: new IconButton(icon: Icon(Icons.menu), onPressed: () => Navigator.pop(context)),
elevation: 0.0,
),
Expanded(
child: Container(
child: Center(
child: Text(
"Menu page!",
style: TextStyle(color: Colors.white, decoration: TextDecoration.none),
),
),
color: Colors.blue,
),
),
]);
}
}
class MyHomePage extends StatelessWidget {
void pushGuillotine(BuildContext context, WidgetBuilder builder) {
Navigator.push(context, new GuillotinePageRoute(builder: builder));
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("This is a title"),
leading: new RotatedBox(
quarterTurns: -1,
child: IconButton(icon: Icon(Icons.menu), onPressed: () => pushGuillotine(context, (context) => MenuPage())),
),
),
body: Container(
color: Colors.blueGrey,
child: Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'This is the home page.',
),
new Text(
'Hello world!',
style: Theme.of(context).textTheme.display1,
),
],
),
),
),
);
}
}
class GuillotinePageRoute<T> extends PageRoute<T> {
GuillotinePageRoute({
#required this.builder,
RouteSettings settings: const RouteSettings(),
this.maintainState: true,
bool fullscreenDialog: false,
}) : assert(builder != null),
super(settings: settings, fullscreenDialog: fullscreenDialog);
final WidgetBuilder builder;
#override
final bool maintainState;
#override
Duration get transitionDuration => const Duration(milliseconds: 500);
#override
Color get barrierColor => null;
#override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final Widget result = builder(context);
assert(() {
if (result == null) {
throw new FlutterError('The builder for route "${settings.name}" returned null.\n'
'Route builders must never be null.');
}
return true;
}());
return result;
}
#override
Widget buildTransitions(
BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
MediaQueryData queryData = MediaQuery.of(context);
var topInset = queryData.padding.top;
Offset origin = Offset((kToolbarHeight / 2.0), topInset + (kToolbarHeight / 2.0));
Curve curve = animation.status == AnimationStatus.forward ? Curves.bounceOut : Curves.bounceIn;
var rotateTween = new Tween(begin: -pi / 2.0, end: 0.0);
Cubic opacityCurve = Cubic(0.0, 1.0, 0.0, 1.0);
return new AnimatedBuilder(
animation: animation,
child: child,
builder: (context, child) {
return Opacity(
opacity: opacityCurve.transform(animation.value),
child: Transform(
transform: Matrix4.identity()..rotateZ(rotateTween.lerp(curve.transform(animation.value))),
origin: origin,
child: child,
),
);
},
);
}
#override
String get barrierLabel => null;
}
It's a stack use the gesture detector's onTapDown which is not available in a floating action button
If you have a widget with no interaction and want to make it clickable use the GestureDetector widget as parent, you can see the example in the link.
--- edit
This answer helps you when you need to make a widget without interaction have some, not exactly what this question is talk about, honest mistake but i could help others..

Flutter: Change height of a container when a button is pressed

The problem here is that the Container doesn't redraw itself after changing the funArg value with the press of a button which should change its height since it's used in its calculation
here is the code :
here is main.dart:
import 'package:flutter/material.dart';
import 'package:sqaure/ui/fun.dart';
Widget rect0;
String rectArg = "20";
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new HomeState();
}
}
class HomeState extends State<Home> {
var list = ["20", "15"];
Widget funTest() {
setState(() {
rectArg = list[1];
rect0 = new Plate(rectArg);
});
}
//final Color primaryColor = Colors.red;
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("rect"),
backgroundColor: Colors.red,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Container(
alignment: Alignment.topCenter,
color: Colors.white,
height: 245.0,
child: new Stack(
children: <Widget>[
Center(
child: Padding(
padding: const EdgeInsets.only(left: 55.0),
child: Row(
children: <Widget>[
//plates
rect0 = new Plate(rectArg),
],
),
),
)
],
),
),
new RaisedButton(onPressed: () {
funTest();
debugPrint(rectArg);
})
],
),
);
}
}
and here is fun.dart:
import 'package:flutter/material.dart';
class Plate extends StatefulWidget {
final String funArg2;
#override
State<StatefulWidget> createState() {
return new PlateState(funArg2);
}
[enter image description here][1]
Plate(this.funArg2);
}
class PlateState extends State<Plate> {
String funArg;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(3.0),
child: Container(
alignment: Alignment.center,
color: Colors.redAccent,
height: funArg != "" ? (9.33 * double.parse(funArg) + 45) : 0.0,
width: 29.0,
child: new Text(
funArg,
style: new TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: funArg.length > 4
? 10.0
: funArg.length > 3 ? 14.0 : 19.0,
),
),
));
}
PlateState(this.funArg);
}
as you can see the height of the container is determined by the child text inside.
screenshot
thank you.
Here is a fixed and commented version of your code. Please read the comments!
The main problem is that you defined Plate as a stateful widget, and stored rectArg in the state! PlateState is only initiated once, until you leave the screen, it's not recreated when the parent widget is rebuilt!
Plate actually doesn't have any internal state, so it should be a StatelessWidget. You should always prefer StatelessWidgets. Understanding why is fundamental for Flutter development!
import 'package:flutter/material.dart';
main() => runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new HomeState();
}
}
// this seems to be a constant, so can put it outside of the class
// or alternatively inside, with "static const" modifier
const list = ["20", "15"];
class HomeState extends State<Home> {
// stateful variables (things that change over time)
// must be inside of your state class
String rectArg = "20";
// we can return void here!
void funTest() {
setState(() {
// state is modified here. this triggers a rebuild/redraw
// that means the build function is called again
// note that we are only the storing the string value, NOT a widget!
rectArg = list[1];
});
}
// this is called every time you setState
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("rect"),
backgroundColor: Colors.red,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Container(
alignment: Alignment.topCenter,
color: Colors.white,
height: 245.0,
child: new Stack(
children: <Widget>[
Center(
child: Padding(
padding: const EdgeInsets.only(left: 55.0),
child: Row(
children: <Widget>[
// DO NOT SET VARIABLES FROM THE BUILD METHOD!
// this is bad:
// rect0 = new Plate(rectArg),
Plate(
funArg: rectArg,
),
],
),
),
)
],
),
),
new RaisedButton(onPressed: () {
funTest();
debugPrint(rectArg);
})
],
),
);
}
}
// Plate is actually a StatelessWidget because it is not interactive and holds no internal state
// All the data (funArg) is passed in from the parent ==> StatelessWidget
// Always prefer stateless widgets!
// That means the widget is completely rebuilt every time the build() method is called in HomeState
class Plate extends StatelessWidget {
// Use named constructor parameters and call the super constructor!
// you can auto-generate the constructor with Android Studio
const Plate({Key key, this.funArg}) : super(key: key);
final String funArg;
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(3.0),
child: Container(
alignment: Alignment.center,
color: Colors.redAccent,
height: funArg != "" ? (9.33 * double.parse(funArg) + 45) : 0.0,
width: 29.0,
child: new Text(
funArg,
style: new TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: funArg.length > 4 ? 10.0 : funArg.length > 3 ? 14.0 : 19.0,
),
),
),
);
}
}
Just in case that you need a StatefulWidget with internal state that also has constructor parameters set by the parent widget (which is quite common): Inside the build method of your State, use the widget property to access the final fields of your widget:
class ColoredCheckbox extends StatefulWidget {
const ColoredCheckbox({Key key, this.color}) : super(key: key);
// this is passed in from the parent, can change when the parent is rebuilt
final Color color;
#override
State<StatefulWidget> createState() => ColoredCheckboxState();
}
class ColoredCheckboxState extends State<ColoredCheckbox> {
// this is internal state, kept even when the parent is rebuilt
bool checked = false;
// build is called when:
// - you call setState from this widget
// - when the parent widget is rebuilt
#override
Widget build(BuildContext context) {
return RaisedButton(
child: Text(checked ? 'X' : '0'),
// use "widget" to access the fields passed in from the parent
color: widget.color,
onPressed: () {
// always call setState when changing internal state
setState(() {
checked = !checked;
});
},
);
}
}

Categories

Resources