Are you a Flutter developer? If so, you’ll know that code snippets can be a life-saver. They’re perfect for when you need to quickly prototype an idea, or when you want to dive into someone else’s code. In this post, we’ve collected some of our favorite Flutter code snippets. Whether you’re just getting started with Flutter or you’re looking for new ways to improve your development process, we hope you find these snippets helpful!
Table of Contents
Animation
Array & List
Map<int, String> products = { 2: "Amethyst +Strawberry Crystal", 5: "Bag Charm", 7: "Christmas Charms", 11: "Lenovo Legion", 57: "Asus ROG Strix", 102: "HP pavilion", }; products.forEach((key, value) { print("$key: $value"); }); for(var key in products.keys){ print("$key: $map[$key]"); } for (MapEntry e in products.entries) { print("${e.key}: ${e.value}"); } for (var value in products.values) { print(value); }
for (var item in myList) { await callOther(item); } await Future.forEach(myList, (item) async { await anotherFutureFunction(item); }); await searchRead(saleTable, args, params).then((items) async { for (var i = 0; i < items.length; i++) { Sale sale = Sale.fromJson(items[i]); sale.product = await searchProductById(sale.product_id); } })
Button
CircleAvatar( backgroundColor: Colors.red, radius: 75, child: TextButton( child: const Center(child: Text('Button')), onPressed: () {}, ), ),
SizedBox( width: 240, child: TextButton( child: const Text('Rounded Text Button'), style: ButtonStyle( padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(16.0)), foregroundColor: MaterialStateProperty.all<Color>(Colors.blue), shape: MaterialStateProperty.all<RoundedRectangleBorder>(RoundedRectangleBorder(borderRadius: BorderRadius.circular(18.0), side: const BorderSide(color: Colors.blue)))), onPressed: () {}), ),
Class & Object
class Square extends Shape { final double radius; Square(super.description, this.double); }
class StockPicking { int? id; String? name; String? origin; double? price; StockPicking({this.id, this.name, this.origin, this.price}); String get stateValue { Map<String, String> values = { "draft": "Draft", "cancel": "Cancelled", "waiting": "Waiting Another Operation", "confirmed": "Waiting Availability", "partially_available": "Partially Available", "available": "Available", "allocated": "Lot Allocated", "assigned": "Ready for Transfer", "done": "Transferred" }; return values.containsKey(state!) ? values[state!].toString() : state!; } bool get isAllocated { return state! == 'allocated'; } set exchangedPrice(double rate){ price = price*rate; } }
Container
Container( height: 200, width: 200, decoration: BoxDecoration( color: Colors.white, borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), bottomLeft: Radius.circular(12), bottomRight: Radius.circular(12), ), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 2, blurRadius: 9, offset: const Offset(0, 5), ), ], ), ),
class GlassContainer extends StatelessWidget { final double? height; final double? width; final Widget? child; const GlassContainer({Key? key, this.child, this.height, this.width}) : super(key: key); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration(boxShadow: [ BoxShadow( blurRadius: 8, spreadRadius: 8, color: Colors.black.withOpacity(0.05), ) ]), child: ClipRRect( borderRadius: BorderRadius.circular(16.0), child: BackdropFilter( filter: ImageFilter.blur( sigmaX: 20.0, sigmaY: 20.0, ), child: Container( width: width ?? 360, height: height ?? 200, decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(16.0), border: Border.all( width: 1.5, color: Colors.white.withOpacity(0.2), )), child: child!, ), ), ), ); } }
<!-- wp:enlighter/codeblock --> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Container( color: Colors.pink, constraints: BoxConstraints( minHeight: 100, minWidth: double.infinity), child: ListView( shrinkWrap: true, children: [ ...List.generate( 5, (index) => Padding( padding: const EdgeInsets.all(8.0), child: Text( 'Text: ${index}' ), ), ), ], ), )</pre> <!-- /wp:enlighter/codeblock -->
Debug & Profiling
var data = ["Good morning", 13354, 7.223344, [], {}, Product('Metal Ring', 300.00)]; if (data[0] is String) print(data[0]); if (data[1] is int) print(data[1]); if (data[2] is! int) print(data[2]); if (data[3] is List) print('List'); if (data[4] is Object) print('Object'); if (data[5] is Product) print(data[5].toString()); if (data[1].runtimeType == int) print('Int'); if (data[3].runtimeType == [].runtimeType) print('List');
Device
var deviceData = <String, dynamic>{}; try { if (kIsWeb) { deviceData = _readWebBrowserInfo(await deviceInfoPlugin.webBrowserInfo); } else { if (Platform.isAndroid) { deviceData = _readAndroidBuildData(await deviceInfoPlugin.androidInfo); } else if (Platform.isIOS) { deviceData = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo); } else if (Platform.isLinux) { deviceData = _readLinuxDeviceInfo(await deviceInfoPlugin.linuxInfo); } else if (Platform.isMacOS) { deviceData = _readMacOsDeviceInfo(await deviceInfoPlugin.macOsInfo); } else if (Platform.isWindows) { deviceData = _readWindowsDeviceInfo(await deviceInfoPlugin.windowsInfo); } } } on PlatformException { deviceData = <String, dynamic>{ 'Error:': 'Failed to get platform version.' }; }
Enumeration
enum Direction { north, south, east, west } var direction = Direction.south; switch (direction) { case Direction.north: print("You are going North!"); break; case Direction.south: print("You are going South!"); break; case Direction.east: print("You are going East!"); break; case Direction.west: print("You are going West!"); break; }
File
//read text file in assets folder Future<String> loadEmojiString(String fileName) async { return await rootBundle.loadString('assets/$fileName.txt'); } //append data to the end of a text file write(String content) async { final directory = await getApplicationDocumentsDirectory(); final File file = File('${directory.path}/somefile.txt'); await file.writeAsString(content, mode: FileMode.append); } //write/override data to a text file write(String content) async { final directory = await getApplicationDocumentsDirectory(); final File file = File('${directory.path}/somefile.txt'); await file.writeAsString(content); }
Function
extension MyCustomList<T> on List<T> { int get slotAvailable => 1000 - length; List<T> operator -() => reversed.toList(); List<List<T>> halve() => [sublist(0, (length/2).round()), sublist((length/2).round())]; }
extension NumberFormat on String { int toInt() { return int.parse(this); } }
class ListCard extends StatefulWidget { final List<Widget>? children; final VoidCallback? onTap; final Color? cardColor; const ListCard({Key? key, this.children, this.onTap, this.cardColor}) : super(key: key); @override State<ListCard> createState() => _ListCardState(); } class _ListCardState extends State<ListCard> { @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(bottom: MyTheme.paddingTop), child: RippleEffect( onTap: widget.onTap, child: Container( padding: const EdgeInsets.all(MyTheme.padding), decoration: BoxDecoration( color: widget.cardColor ?? MyTheme.cardColor, border: Border.all( color: widget.cardColor ?? MyTheme.cardColor, ), borderRadius: MyTheme.radius), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: widget.children!, )), ), ); } }
Icon
dev_dependencies: flutter_test: sdk: flutter flutter_launcher_icons: ^0.9.2 flutter_icons: android: true ios: true image_path: "assets/icon/my_custom_launcher.png"
class CounterIcon extends StatelessWidget { final Icon? icon; final int? counter; const CounterIcon({Key? key, this.icon, this.counter}) : super(key: key); @override Widget build(BuildContext context) { return Stack(children: <Widget>[ icon!, Positioned( right: 0, child: Container( padding: const EdgeInsets.all(1), decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(6), ), constraints: const BoxConstraints( minWidth: 16, minHeight: 16, ), child: Text( '$counter', style: const TextStyle( color: Colors.white, fontSize: 10, ), textAlign: TextAlign.center, ), ), ) ]); } }
Image
ColorFiltered( colorFilter: const ColorFilter.mode( Colors.grey, BlendMode.saturation, ), child: FadeInImage.assetNetwork( image: "https://cdn.pixabay.com/photo/2022/04/06/20/29/airplane-7116299_960_720.jpg", placeholder: "https://cdn.pixabay.com/photo/2022/04/06/20/29/airplane-7116299_960_720.jpg", ), )
CircleAvatar( backgroundImage: Image.network("https://cdn.pixabay.com/photo/2022/04/18/19/51/rocks-7141482_960_720.jpg").image, backgroundColor: Colors.transparent, radius: 100, )
CircleAvatar( backgroundImage: NetworkImage('https://cdn.pixabay.com/photo/2022/04/18/16/16/ship-7140939_960_720.jpg'), radius: 200 )
class BezierCurveClipper extends CustomClipper<Path> { @override Path getClip(Size size) { var waveHeight = 10; Path path = new Path(); final lowPoint = size.height - waveHeight; final highPoint = size.height - waveHeight*2; path.lineTo(0, size.height); path.quadraticBezierTo( size.width / 4, highPoint, size.width / 2, lowPoint); path.quadraticBezierTo( 3 / 4 * size.width, size.height, size.width, lowPoint); path.lineTo(size.width, 0); return path; } @override bool shouldReclip(CustomClipper<Path> oldClipper) => false; }
Container( decoration: BoxDecoration(color: Colors.red, shape: BoxShape.circle), height: 300, width: 300, child: ClipOval( child: Image.network( "https://cdn.pixabay.com/photo/2017/03/01/05/13/table-setting-2107600_960_720.jpg", fit: BoxFit.fitHeight,), ), )
Keyboard
Layout
Scaffold( backgroundColor: Colors.blue, body: Center( child: FlutterLogo( size: 200, ), ), )
import 'package:anime_timer/constant/theme.dart'; import 'package:anime_timer/ui/common/appbar.dart'; import 'package:flutter/material.dart'; class MyScaffold extends StatelessWidget { final Widget? child; final List<Widget>? action; final Widget? floatingActionButton; const MyScaffold({Key? key, this.child, this.action, this.floatingActionButton}) : super(key: key); @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Colors.orangeAccent, Colors.deepOrange], )), child: Scaffold( appBar: MainAppBar(action: action ?? []), body: SafeArea( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), child: SizedBox( width: MediaQuery.of(context).size.width, child: child!, ), ), ), ), floatingActionButton: floatingActionButton, ), ); } }
import 'package:flutter/material.dart'; class ResponsiveLayout extends StatelessWidget { final Widget? mobileLayout; final Widget? desktopLayout; final double breakPoint = 640.0; const ResponsiveLayout({Key? key, this.mobileLayout, required this.desktopLayout}) : super(key: key); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { if (constraints.maxWidth >= breakPoint) { return desktopLayout!; } else { return mobileLayout != null ? mobileLayout! : desktopLayout!; } }, ); } }
class WaveShape extends CustomClipper<Path> { @override getClip(Size size) { double height = size.height; double width = size.width; var p = Path(); p.lineTo(0, 0); p.cubicTo(width * 1 / 2, 0, width * 2 / 4, height, width, height); p.lineTo(width, 0); p.close(); return p; } @override bool shouldReclip(CustomClipper oldClipper) => true; } class BottomWaveShape extends CustomClipper<Path> { @override getClip(Size size) { double height = size.height; double width = size.width; var p = Path(); p.lineTo(0, 0); p.cubicTo(width * 1 / 2, 0, width * 2 / 4, height, width, height); p.lineTo(0, height); p.close(); return p; } @override bool shouldReclip(CustomClipper oldClipper) => true; }
//view detail link for full source code @override Widget build(BuildContext context) { return Stack( fit: StackFit.expand, children: [ _video(context), _top(), _bottom(), _right(context), ], ); }
class ChatBox extends StatefulWidget { @override _ChatBoxState createState() => _ChatBoxState(); } class _ChatBoxState extends State<ChatBox> { @override Widget build(BuildContext context) { return Container( height: MediaQuery.of(context).size.height - 150, padding: EdgeInsets.fromLTRB(36.0, 16.0, 36.0, 16.0), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Avatar(), SizedBox(width: 8.0), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Name, 8:30PM', style: TextStyle(color: Theme.secondaryTextColor), ), Container( padding: EdgeInsets.all(8.0), decoration: BoxDecoration( color: Colors.blueAccent, borderRadius: BorderRadius.circular(8.0)), child: Text('Hello\nMy test message')), ], ), ], ), SizedBox(height: 16.0), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Container( padding: EdgeInsets.all(8.0), decoration: BoxDecoration( color: Colors.grey.shade200, borderRadius: BorderRadius.circular(8.0)), child: Text('Hello')), ], ), ], ), ); } }
List
FutureBuilder<List<StockMove>?>( future: _futureStockMoves, builder: (ctx, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { return const ErrorText(); } else if (snapshot.hasData) { final moves = snapshot.data as List<StockMove>; return Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ if(widget.picking!.picker_release!) Row( mainAxisAlignment: MainAxisAlignment.start, children: [ TextButton(onPressed: (){ setState(() { }); }, child: const Text("Press Me", style:TextStyle(color: MyTheme.highlightColor),)) ],), if (moves.isNotEmpty) ...moves .map((item) => Text(item.name)) else const Text('No product') ], ); } } // Displaying LoadingSpinner to indicate waiting state return CenterProgressIndicator(); } )
Menu & Navigation
class WaveClip extends CustomClipper<Path> { @override Path getClip(Size size) { Path path = new Path(); final lowPoint = size.height - 30; final highPoint = size.height - 60; path.lineTo(0, size.height); path.quadraticBezierTo( size.width / 4, highPoint, size.width / 2, lowPoint); path.quadraticBezierTo( 3 / 4 * size.width, size.height, size.width, lowPoint); path.lineTo(size.width, 0); return path; } @override bool shouldReclip(CustomClipper<Path> oldClipper) { return false; } }
import 'package:flutter/material.dart'; class StackPage extends StatefulWidget { @override _StackPageState createState() => _StackPageState(); } class _StackPageState extends State<StackPage> with SingleTickerProviderStateMixin { AnimationController _controller; @override void initState() { _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 500)); super.initState(); } void _toggle() { setState(() { _controller.isDismissed ? _controller.forward() : _controller.reverse(); }); } FlatButton _menuItem(IconData icon, String text, VoidCallback onPressed){ return FlatButton(onPressed: onPressed, child: Row( children: [ Icon(icon, color: Colors.white,), SizedBox(width: 8,), Text(text, style: TextStyle(color: Colors.white),) ], )); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (BuildContext context, Widget child) { double slide = 50 * _controller.value; double scale = 1 - (_controller.value * 0.5); return Stack( children: [ Container( width: double.infinity, color: Colors.lightBlueAccent, child: Padding( padding: const EdgeInsets.only( top: 50.0, left: 16.0, right: 16.0, bottom: 16.0), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Navigation', style: Theme.of(context).textTheme.headline6, ), _menuItem(Icons.home, 'Home', (){}), _menuItem(Icons.pages, 'Page 1', (){}), _menuItem(Icons.palette, 'Page 2', (){}), _menuItem(Icons.close, 'Close Menu', () => _toggle()), ], ), flex: 5, ), Expanded( child: Container(), flex: 5, ) ], ), ), ), Transform( transform: Matrix4.identity() ..translate(slide) ..scale(scale), alignment: Alignment.centerRight, child: Scaffold( appBar: AppBar( title: Text('Example'), actions: [ IconButton( icon: Icon(Icons.dehaze), onPressed: () { _toggle(); }, ) ], ), body: Center( child: Text('Main page'), ), ), ), ], ); }, ); } @override void dispose() { _controller.dispose(); super.dispose(); } }
@override Widget build(BuildContext context) { return Drawer( child: ListView( children: [ Padding( padding: EdgeInsets.all(16.0), child: Text('Gmail', style: TextStyle(fontSize: 24, color: Colors.redAccent)), ), Divider(color: Colors.grey), _tile(Icons.all_inbox, 'All inboxes', -1, () { setState(() { _selectedLabel = 'All inboxes'; }); }), Divider( color: Colors.grey, indent: 70.0, ), _tile(Icons.inbox, 'Primary', 5, () {}), _tile(Icons.group, 'Social', -1, () {}), _tile(Icons.label, 'Promotions', -1, () {}), Divider( color: Colors.grey, indent: 70.0, ), _tile(Icons.star_border_outlined, 'Starred', 15, () {}), _tile(Icons.schedule, 'Snoozed', -1, () {}), _tile(Icons.label_important_outline_sharp, 'Important', 100, () { setState(() { _selectedLabel = 'Important'; }); }), _tile(Icons.send_outlined, 'Sent', -1, () {}), _tile(Icons.schedule_send, 'Scheduled', -1, () {}), _tile(Icons.insert_drive_file_outlined, 'Draft', -1, () {}), _tile(Icons.mail, 'All mail', -1, () {}), _tile(Icons.report_gmailerrorred_outlined, 'Spam', -1, () { setState(() { _selectedLabel = 'Spam'; }); }), _tile(Icons.restore_from_trash_outlined, 'Trash', -1, () {}), Divider( color: Colors.grey, indent: 70.0, ), Padding( padding: const EdgeInsets.all(16.0), child: Text('LABELS'), ), _tile(Icons.label_outline, '[Imap]/Sent', -1, () {}), _tile(Icons.label_outline, '[Imap]/Trash', -1, () {}), _tile(Icons.label_outline, 'Work', -1, () {}), Divider( color: Colors.grey, indent: 70.0, ), _tile(Icons.add, 'Create New', -1, () {}), Divider( color: Colors.grey, indent: 70.0, ), _tile(Icons.settings_outlined, 'Settigs', -1, () {}), _tile(Icons.feedback_outlined, 'Send Feedback', -1, () {}), _tile(Icons.help_outline, 'Help', -1, () {}), ], ), ); }
bottomNavigationBar: BottomAppBar( shape: CircularNotchedRectangle(), notchMargin: 8.0, clipBehavior: Clip.antiAlias, child: Container( height: kBottomNavigationBarHeight, child: Container( decoration: BoxDecoration( color: Colors.white, border: Border( top: BorderSide( color: Colors.grey, width: 0.5, ), ), ), child: BottomNavigationBar( currentIndex: _currentIndex, backgroundColor: Colors.blue, selectedItemColor: Colors.white, onTap: (index) { setState(() { _currentIndex = index; }); }, items: [ BottomNavigationBarItem( icon: Icon(Icons.category), label: 'Category'), BottomNavigationBarItem(icon: Icon(Icons.home), label: ''), BottomNavigationBarItem( icon: Icon(Icons.settings_outlined), label: 'Setting') ]), ), ), )
class RoundAppBar extends StatelessWidget with PreferredSizeWidget{ final double barHeight = 50; final String title; RoundAppBar({Key key, this.title}) : super(key: key); @override Size get preferredSize => Size.fromHeight(kToolbarHeight + barHeight); @override Widget build(BuildContext context) { return AppBar( title: Center(child: Text(title)), shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical( bottom: Radius.circular(48.0), ), ), actions: [ Icon(Icons.dehaze) ], ); } }
class MainAppBar extends StatelessWidget implements PreferredSizeWidget { final double barHeight = 20.0; const MainAppBar({Key? key}) : super(key: key); @override Size get preferredSize => Size.fromHeight(kToolbarHeight + barHeight); @override Widget build(BuildContext context) { return AppBar( backgroundColor: Colors.green, elevation: 0, centerTitle: true, leading: ModalRoute.of(context)!.canPop ? IconButton( icon: const Icon( Icons.arrow_back, color: Colors.white, ), onPressed: () => Navigator.of(context).pop(), ) : null, title: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text('App Title') ], ), ); } }
//close a screen with a message, previous page can check this message to know what happened on the 2nd screen. Navigator.pop(context, 'any success message here')
DropdownButton<String>( value: _selectedValue, isExpanded: true, items: [ DropdownMenuItem<String>( value: "jaav", child: Text( "Java", style: TextStyle(color: Colors.red), ), ), DropdownMenuItem<String>( value: "kotlin", child: Text( "Kotlin", style: TextStyle(color: Colors.blue), ), ), ], onChanged: (value) { setState(() { _selectedValue = value; }); }, hint: Text( "Category", ), )
Number
String str = "182000000 and 2670000. That’s how many seconds I’ve spent thinking."; String? numStr = RegExp(r"\d+").firstMatch(str)!.group(0); int num = int.parse(numStr!); print(num); // 182000000 String numbers = "56.20 kg"; double? d = double.tryParse(numbers.replaceAll(RegExp(r'[^0-9\.]'), '')); print(d); //56.2
Operating System
import 'package:flutter/foundation.dart' show kIsWeb; import 'dart:io' show Platform; if (kIsWeb) { print("This is a website"); } if (Platform.isAndroid) { } else if (Platform.isIOS) { } else if (Platform.isFuchsia) { } else if (Platform.isWindows) { } else if (Platform.isMacOS) { } else if (Platform.isLinux) { }
Progress Indicator
Text
class RoundedTextField extends StatelessWidget { final String? hintText; final IconData? icon; final Color? color; final Color? backgroundColor; final ValueChanged<String>? onChanged; final TextEditingController? controller; const RoundedTextField( {Key? key, this.hintText, this.icon, this.onChanged, this.color = Colors.white, this.backgroundColor = Colors.blueAccent, this.controller}) : super(key: key); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.circular(36), ), child: TextField( controller: controller, onChanged: onChanged, cursorColor: color, decoration: InputDecoration( icon: Icon( icon, color: color, ), hintText: hintText, hintStyle: TextStyle(color: color), border: InputBorder.none, ), ), ); } }
//The default font size is 14 logical pixels. MaterialApp( theme: ThemeData( textTheme: const TextTheme( bodyText1: TextStyle(fontSize: 18.0), bodyText2: TextStyle(fontSize: 20.0), button: TextStyle(fontSize: 16.0), ), ), home: Scaffold( body: Center(child: Text("Font size is 18")), ), )
Theme
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( backgroundColor: Colors.orange, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text("First Line"), const Text("Second Line"), ], ), ), ), ); } }
Timer
Future.delayed(Duration(milliseconds: 500), () { print("Call a method after 0.5 seconds"); }); Timer(Duration(seconds: 10), () { print("This line is called after 10 seconds"); });
class CountDownTimeWidget extends StatefulWidget { final int? endTime; const CountDownTimeWidget({Key? key, required this.endTime}) : super(key: key); @override State<CountDownTimeWidget> createState() => _CountDownTimeWidgetState(); } class _CountDownTimeWidgetState extends State<CountDownTimeWidget> { @override Widget build(BuildContext context) { return CountdownTimer( endTime: widget.endTime!, widgetBuilder: (_, CurrentRemainingTime? time) { if (time == null) { return Container(); } return Text("${time.hours.toString().padLeft(2, "0")}:${time.min.toString().padLeft(2, "0")}:${time.sec.toString().padLeft(2, "0")}", style: const TextStyle( fontSize: 18, )); }, ); } }
Troubleshoot
if (mounted) { setState (() => _sales = []); }