“50+ Flutter & Dart Tips & Tricks” is a comprehensive guide that provides developers with practical and actionable advice for building better mobile applications with Flutter and Dart. The guide includes tips and tricks for optimizing application performance, improving code readability and maintainability, and solving common development challenges. With over 50 tips and tricks, this guide is a valuable resource for beginner and experienced Flutter developers looking to improve their skills and create high-quality mobile applications more efficiently.
1. Flutter Style Re-usability
Flutter is a powerful framework for making cross-platform mobile apps with visually appealing user interfaces. It encourages code reuse through themes, custom widgets, mixins, and converting styles to variables or constants. These approaches ensure app consistency, simple customization, and upgrades. Custom widgets combine visual appearance and behavior into a single component, while mixins enable code reuse across different classes, sharing style-related functionality without inheritance or duplication.
Use these predefined text styles!
Text(
"Title",
style:Theme.of(context).textTheme.title),
Text(
"Headline",
style:Theme.of(context).textTheme.headline),
Text(
"Subhead",
style:Theme.of(context).textTheme.subhead),
Text(
"Button",
style:Theme.of(context).textTheme.button),
Text(
"Caption",
style:Theme.of(context).textTheme.caption),
Text(
"Body1",
style:Theme.of(context).textTheme.body1),
Text(
"Body2",
style:Theme.of(context).textTheme.body2),
2. Flutter Spacer Widget
The Flutter Spacer widget is a handy tool that allows you to control the spacing and alignment within your Flutter layouts. With just a single line of code, you can easily add empty space between your UI elements or adjust their positioning. Whether you need to create even spacing between widgets or fine-tune the alignment within a row or column, the Spacer widget has got you covered. Its flexibility and simplicity make it a go-to choice for achieving clean and organized layouts in your Flutter app. Say goodbye to manual padding calculations and let the Spacer widget handle your spacing needs effortlessly.
Creates space between widgets
Row(
children:[
SomeWidget(),
Container(width:25),
SomeWidget(),
Container(width:25),
SomeWidget(),
Container(width:25),
SomeWidget(),
Container(width:25),
SomeWidget(),
Container(width:25),
]
)
Row(
children:[
SomeWidget(),
Spacer(),
SomeWidget(),
Spacer(),
SomeWidget(),
Spacer(),
SomeWidget(),
Spacer(),
SomeWidget(),
Spacer(),
]
)
3. Flutter FractionallySizedBox
Use this widget if you need the same proportion the height and width equal to a sized box
FractionallySizedBox(
widthFactor: 0.75,
heightFacter: 0.75,
child: Container(color: Color.orange),
)
The fraction value will range between 0.0 to 1.0
4. Flutter Parse Strings
Convert numerical strings into int and doubles
integers
var fooParsed = int.parse(5800);
print(fooParsed);//5800
doubles
var fooParsedDouble = int.parse(84545.25616);
print(fooParsedDouble);//84545.25616
5. Flutter Catching Exceptions
Catch the exceptions like a pro! Use try-catch block to catch the exceptions
fooLogin{
required String email,
required String password
}){
try{
var user =await _data.login(email,password);
} on FechDataException catch(error){
print('Exception Data : $error');
}
}
6. Using Flutter null-aware operators
Using null-aware operators while verifying the null in Dart helps you decrease the amount of code necessary to cope with possibly null references.
//insted of
if(title == null){
title = "Title";
}
//use dellow
title ?? = "Title";
7. Using Flutter ListView.separated()
Want to add the separator to your Flutter ListView?
Go for the ListView.separated()
ListView.separated(
itemCount: Items.length,
itemBuilder: (ctx,i) => ExampleItem(),
//Separator can be any widget.
separatorBuilder: (ctx,i)=>const Divider(),
);
8. Do not explicitly initialize the variable to null in Flutter
Adding = null is redundant and unneeded
//Good
var title;
//Bad
var title = null;
9. Use a Flutter Ternary Operator instead of the if-else to shorter your Dart code.
//Insted of this
bool isAndroid = true;
getDeviceType(){
if(isAndroid)(return "Android";)
else{return "Other";}
}
//Use bellow
bool isAndroid = true;
isAndroid ? "Android" : "Other";
10. Do you want to change the theme of a particular widget in Flutter?
Simply wrap the widget with the Theme Widget and supply the ThemeData() function.
Theme(
data:ThemeData(...),
child:TextFormField(
decoration: const InputDecoration(
icon: (Icons.person),
hintText:'What do people call you?',
labelText:'Name *',
),
validator: (value) {
return value!l.contains('@')? 'Do not use @ char':null;
}
),
)
11. Flutter Cascade Notation Method Chaining on Steroids
Cascades Notation (..) allows you to chain together a series of operations on the same object.
Furthermore, fields (data members) can be retrieved using the same method.
class Person {
String name;
int age;
Person(this.name, this.age);
void data() => print("$name is $age years old.");
}
//Without Cascade Notation
Person person = Person("Richard", 50);
person.age = 22;
person.name +=" Parker";
person.data();
//Cascade Notation with Object of Person
Person("Jian", 21)
..age = 22
..Name +=" Yang"
..data();
//Cascade Notation with List
<String>["Natasha", "Steve", "Peter", "Tony"]
..sort()
..forEach((name) => print("\n$name"));
12. In Flutter, do you want to log data to the system console?
You may view it in the system console by using the print() method. If your output is too
much, then Android sometimes discards some log lines. To avoid this, you can use debugPrint().
If you’re conducting long-term or background work, you may additionally log your print calls to disk.
13. Have trouble displaying splashes using an InkWell in Flutter?
Use an Ink widget! Because the Ink widget uses the same widget as the InkWell widget,
class InkWellCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
(
return Card(
elevation: 3.0,
child: Ink(
child:InkWell (
onTap: () => print("Ordering.."),
child: Text("Order Bagels"),
),
),
);}
}
14. Implement assert() messages in Dart.
Do you know that if your assert fails, you may toss your message? assert() accepts an optional message, which you may use to pass your message.
assert(title != null, "Title string cannot be null.");
15. Flutter Prefer single quotes for strings
Use double quotes for nested strings or (optionally) for strings that contain single quotes. For all other strings, use single quotes.
final String name = 'Flutter And Dart Tips and Triks';
print('Hello ${name.split(" ")[0]}');
print('Hello ${name.split(" ")[2]});
16. Set the background image to your Container in Flutter.
Do you want to change the background image of your Container? And you’re doing it with a Stack? There is a better way to achieve this purpose. To place the picture in the container, you may use decoration.
Container(
width: double.maxFinite,
height: double.maxFinite,
decoration:BoxDecoration(
image:DecorationImage(
image:NetworkImage('https://bit.ly/2322da),
),),
child:Center(
child:Text('Flutter.dev',
style: (color: Colors.red),),),
);
17. Check if the release mode or not in Flutter
This is a constant that holds true if the program was compiled in Dart. with the ‘-Ddart.vm.product=true’ flag.
import 'package:flutter/foundation.dart';
print('Ils Release Mode: $kReleaseMode');
18. Apply HitTestBehavior.opaque on GestureDetector to make the entire size of the gesture detector a hit region in Flutter
If your GestureDetector isn’t picking up gestures in a transparent/translucent idget, make sure to set its behavior to HitTestBehavior.opaque so it’ll capture those events.
GestureDetector(
behavior: HitTestBehavior.opaque,
ontTap: () => print('Tap!'),
child: Container(
height: 250
width: 250
child: Center(child: Text('Gesture Test')),
),
),
19. You can iterate through a map in a null-safe manner using entries in Flutter.
for (var entry in items.entries) {
//Print the keys and values
print('${entry.key}: ${entry.value}');
}
20. You can wait for the results of multiple futures to be complete using Future.wait.
class someAPI {
  Future<int> getThings() => Future.value(3000);
  Future<int> getItems() => Future.value(300);
  Future<int> getStuff() => Future.value(30);
}
final api = someAPI();
final values =
await Future.wait([
  api.getThings(),
  api.getltems(),
  api.getStuff(),
])
21. GridView.count may be used to construct a two-tile-wide grid in portrait mode and a three-tile-wide grid in landscape mode.
Fleible (
  child:GridView.count (
    crossAxisCount:
      (orientation == Orientation.portrait) ? 2:3,
    mainAxisSpacing: 4.0,
    crossAxisSpacing: 4.0,
    padding:const EdgeInsets.all(4.0),
    childAspectRatio:
    (orientation == Orientation.portrait) ? 1.0:1.3,
    children: someList.map((catData) =>
    aListitemWidget(catData)).toList(),
   ),
);
22. Using Random from Dart, you may choose one item at random from a list:math in Flutter
import 'dart:math';
...
int min = 0;
int max = someList.length - 1;
Random rnd = new Random();
int r = min + rnd.nextInt(max - min);
return someList[r];
23. You can use the service library to lock the device’s orientation in Flutter.
import 'package"flutter/services.dart';
...
void main() async{
  await
  SystemChrome.setPreferredOrientations
  [DeviceOrientation.portraitUp]);
  runApp(Appan());
}
24. Platform-specific code may be written using the dart:io library.
import 'dart.io' show Platform
'''
if (Platform.isIOS) {
  doSomethingforIOS();
}
if (Platform.isAndroid) {
  doSomethingforAndroid();
}
25. Any color can be converted to a Material Color.
const Map color = {
50:Color.fromRGBO(255, 207, 68, .1),
100:Color.fromRGBO(255, 207, 68, .2),
200:Color.fromRGBO(255, 207, 68, .3),
300:Color.fromRGBO(255, 207, 68, .4),
400:Color.fromRGBO(255, 207, 68, .5),
500:Color.fromRGBO(255, 207, 68, .6),
600:Color.fromRGBO(255, 207, 68, .7),
700:Color.fromRGB(255, 207, 68, .8),
800:Color.fromRGB(255, 207, 68, .9),
900:Color.fromRGB(255, 207, 68, 1),
};
const MaterialColor custom_color =MaterialColor(OxFFFFCF44, color);
26. To conceal the status bar, utilize the library of the service.
import 'package:flutter/services.dart';
void main(){
SystemChrome.setEnabledSystemUiMode(
SystemUiMode.manual,
overlays: [],
);
}
27. The Expanded widget allows you to resize the widgets to fit within a row or column.
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Expanded(
child:Image.asset('images/pic1.jpg'),
),
Expanded(
child:Image.asset('images/pic2.jpg'),
),
Expanded(
child:Image.asset('images/pic3.jpg'),
),
]
);
28. Use the Hero widget to animate a widget from one screen to the next screen.
A symbol on the first page, for example, may fly to the second page.
//Page 1
Hero(
tag:"FlyingHero",
child:Icon(
Icons.party_mode_outlined,
size: 50.0,
),
);
//Page 2
Hero(
tag:"FlyingHero",
child:Icon(
Icons.party_mode_outlined,
size: 150.0,
),
);
29. Use Stack to overlap widgets. The first widget will be at the bottom, and the last widget will be at the top.
Stack(
children:[
Container(
width: 100,
height: 100,
color: Colors.red,
),
Container(
width: 90,
height: 90,
color: Colors.green,
),
Container(
width: 80,
height: 80,
color: Colors.blue,
),
],
);
30. Enums and extension methods can help make your code easier to read.
Converting enums to strings is done in this example.
enum Cities { Tehran, Zanjan, Tabriz}
extension ToString on Cities {
String get name => toString().split('.').last;
}
void main() {
print(Cities.Tehran.name);
print(Cities.Zanjan.name);
print(Cities.Tabriz.name);
}
31. Dart allows you to build a callable class, which lets you to use an instance of the class as a function.
class WelcomeToTheCity {
//Difining call method
String call(String str1, String str2, String str3) =>'Welcome to $str1$str2$str3;
}
void main(){
var welcomeToCity = WelcomeToTheCity();
//Calling the class through its instance
var welcomeMsg = welcomeToCity('SanDiego','CA','USA');
print(welcomeMsg);
}
32. InkWell may be used to provide a ripple effect to offer a visual experience for touch reaction.
inkWell(
splashColor: Colors.red,
onTap: () {},
child: Card(
elevation: 5.0.
child: Text('Click This',
style:Theme.of(context).text Theme.headline2,
),
),
);
33. You can have a background color behind the text and add a curve at the start and the end.
Center(
child: Text('This is a very nice text ',
style: TextStyle(
fontWeight: FontWeight,
color: Colors.white,
fontSize: 20,
background: Paint()
..strokWidth =30.0
..color = Colors.red
..style = PaintingStyle.stroke
..strokeJoin = StrokJoin.round),
),
)
34. FittedBox may be used to scale and fit the child widget within it preventing its child widgets from expanding beyond a certain size.
It rescales them to fit the available space.
Center(
child: Row(children: [
Expanded(
chiled:FittedBox(
child:Text("When looking at a page's layout, it is a well-known truth that "the reader will be distracted by the readable." content." ,
maxLines: 1,
style: (fontSize: 23),
),
),
),
]
),
)
35. Use the ListView to create a horizontal list by setting the
scrollDirection parameter to Axis.horizontal
ListView(
scrollDirection: Axis.horizontal,
children: [
///Some object
],
);
36. Center the F.A.B. by setting the floatingActionButtonLocation parameter as below.
Scaffold(
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
floatingActionButton:
FloatingActionButton(
onPressed: () {},
child: Icon(Icons.settings_voice),
),
...
);
37. You can provide an action label in SnackBar to act when pressed on it as below
final snackBar =SnackBar(
content:
const Text('Amazing SnackBar!'),
action:SnackBarAction(
label:'Undo',
onPressed: () {
//Do somthing
},
),
);
38. Make use of the barrier. The dismissible attribute prevents the AlertDialog from being dismissed when the user touches on the screen outside the alert box.
showDialog(
context: context,
barrierDismissible:false,
builder: (BuildContext context) =>
AlertDialog(
title:const Text('This is a title'),
content:
const Text('This is a description'),
actions: [
TextButton(
onPressed: () =>
Navigator.pop(context,'Cancel'),
child: const Text('Cancel'),
),
.
.
.
TextButton(
onPressed: () =>
Navigator.pop(context, 'OK’),
child: const Text('Ok’),
),
],
),
);
39. You can create a circular icon button using ElevatedButton.
Check out the following example.
ElevatedButton(
onPressed: () {}.
style:
ElevatedButton.styleFrom(
shape:CircleBorder(),
padding:EdgeInsets.all(30),
),
child: Icon(
Icons.add,
size: 50,
),
)
40. The ShaderMask widget may be used to give its child a gradient look and feel.
Center(
child: ShaderMask(
blendMode: BlendMode.srcin,
shaderCallback: (Rect bounds) {
return const LinearGradient(
colors: [Colors.red, Colors.green],
tileMode: TileMode.clamp,
).createShader(bounds); },
child:
const Text('This is a colorful Text',
style:TextStyle (fontSize: 36),
),
),
)
41. If the size of a certain kid changes, AnimatedSize automatically transitions its size over a given time period.
double _size =500;
bool _large = false;
void _updateSize() {
setState(() {
_size = _large ? 250.0 : 100.0 ;
_large = !_large;
});
}
GestureDetector(
onTap: () => _updateSize(),
child: Container(
color: Colors.amberAccent,
child: AnimatedSize(
vsync:this,
curve: Curves.easeInCirc,
duration:
const Duration(seconds: 2),
child:FlutterLogo(size: _size),
),
),
);
42. You can use the ColorFiltered widget to apply a color filter to its child widgets.
Column(
children: [
//The Original image
Image.netWork(_imageUrl),
ColorFiltered(
colorFilter:
const ColorFilter.mode(Colors.grey,
BlendMode.saturation),
child: Image.network (_imageUrl),
),
]
);
43. You can create multiple shadows for a Text widget.
Text('Important Text',
style: TextStyle(
color: Colors.black,
fontSize: 50,
fontWeight: FontWeight.bold,
shadows: [
Shadow(
color: Colors.red[500]!,
offset:const Offset(-50, -50),
blurRadius: 5),
Shadow(
color: Colors.green[200]!,
offset: const Offset(50, 50),
blurRadius: 5),
],
),
);
44. LayoutBuilder aids in the building of a widget tree whose size is determined by the parent widget.
LayoutBuilder(
builder: (context, constraints) {
if(constraints.maxWidth >= 750) {
return Container(
color: Colors.green,
height: 100,
width: 100,
);
}else{
return Container(
color: Colors.yellow,
height: 100,
width: 100,
);
}
},
)
45. The AnimatedContainer widget is an animated container widget.
It can be animated by changing the properties’ values.
AnimatedContainer (
width: _width,
height: height,
decoration:BoxDecoration(
color: _color,
borderRadius: _borderRadius,
),
duration:Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
)
46. The SliverAppBar widget provides a floating app bar.
SliverAppBar (
pinned: _pinned,
snap: _snap,
floating: _floating,
expandedHeight: 160.0,
flexibleSpace:
const FlexibleSpaceBar(
title: Text('SilverAppBar'),
background:FlutterLogo(),
),
)
47. When the opacity of a child changes, the AnimatedOpacity Widget dynamically transitions the opacity over time.
AnimatedOpacity(
opacity: _opacity,
duration: const Duration(seconds: 1),
curve: Curves.bounceinOut,
//The animatedOpacity widget must be a child of the green box.
child:Container(
width: 200.0,
height: 200.0,
color: Colors.green,
),
)
T
48. The wrap is a widget that shows its children in either horizontal or vertical runs.
It will attempt to arrange each kid on the main axis close to the preceding child.
If there is insufficient room, it will generate a new run in the cross.axis close to its current offspring.
Wrap(
children:List.generate(10,
(index) =>Container(
margin:const EdgeInsets.all(10),
color: Colors.green,
height: 100,
width: 100,
),
),
);
49. The SlideTransition Widget animates the position of a widget relative to its normal position.
SlideTransition(
position: _offsetAnimation,
child:const Padding(
padding: EdgeInsets.all(8.0),
child: FlutterLogo(size: 150.0),
),
)
50. The FadeTransition Widget fades a widget in and out by animating its opacity.
FadeTransition (
opacity: _animation,
child:const Padding(
padding:EdgeInsets.all(8),
child:FlutterLogo(),
),
)
51. The AnimatedCrossFade Widget switches between two children and animates their sizes.
AnimatedCrossFade(
crossFadeState: _isFirst
? CrossFadeState.showFirsy:
CrossFadeState.showSecond,
duration: const Duration(seconds: 1),
firstCurve: Curves.easeInCubic,
secondCurve: Curves.easeInCirc,
firstChild:
const FlutterLogo(style:
FlutterLogoStyle.horizontal,
size: 100.0),
secondChild:
const FlutterLogo(style:
FlutterLogoStyle.stacked,
size: 100.0),
)
52. When the child is long-pressed, the CupertinoContextMenu Widget appears as a full-screen modal route.
CupertinoContextMenu(
child: Container(color: Colors.red),
actions: [
CupertinoContextMenuAction(
child:const Text('Action one'),
onPressed: () =>
Navigator.pop(context),
),
],
)
53. The BackdropFilter Widget applies a filter to the existing painted content.
BackdropFilter (
filter:ImageFilter.blur(
sigmax: 10.0,
sigmayY: 10.0,
),
child:Container(
color:Colors.black.withOpacity (0.2),
),
)
54. To create space between widgets, use the Spacer Widget.
Column(
   children: [
  Container(
    color: Colors.red,
    height: 50,
    width: 50,
   ),
  Spacer(),
  Container(  Â
    color: Colors.green,
    height: 50,
    width: 50,
  ),
  ],
)
55. A widget called the FractionallySizedBox Widget restricts the size of the child to a portion of the entire amount of available space.
FractionallySizedBox(
   widthFactor: 0.5,
   heightFactor: 0.25,
   child:ElevatedButton(
  onPressed: () {},
  child: Text('Click Me'),
   ),
),
56. Use the AnimatedSwitcher widget to create animation when switching between two widgets.
AnimatedSwitcher(
  duration: const Duration(milliseconds: 500),
  transitionBuilder: (Widget child,
  Animation animation) {
  return ScaleTransition(child: child,scale: animation)
  },
  child: Text('$_count',
  key: ValueKey(_count) , style:
    Theme.of(context).textTheme.headline4,
  ),
),
57. Use the CupertinoAlertDialog to create an iOS-style widget that informs the user about situations that require acknowledgement.
CupertinoAlertDialog(
  title:Text("This is the title"),
  content:Text("This is the content"),
  actions: [
  CupertinoButton(
    child: Text('Cancel'),
    onPressed: () => Navigator.of(ctx).pop();
  ),
  CupertinoButton(
    child: Text('I agree'),
    onPressed: (){
    print('I agreed'),
    Navigator.of(ctx).pop();
    },
    ),
  ],
)
58. Create an iOS-style button with the CupertinoButton Widget that accepts text or an icon that fades out and in on touch.
Container(
  child:Center(
  child:CupertionButton(
    onPressed: () {},
    child: Text("CupertionButton Widget"),
  ),
  ),
),
Container(
  child:Center(
  child:CupertionButton.filled(
    onPressed: () {},
    child: Text("CupertionButton Widget"),
  ),
  ),
),
59. Flow is a widget that arranges its child widgets based on FlowDelegate.
Flow(
delegate: FlowMenuDelegate(
menuAnimation: menuAnimation),
children:
menultems.map(
(IconData icon) =>
flowMenultem(icon)).toList(),
),
);
60. You can fix the text overflow error with the Flexible Widget.
Flexible(
child:Text('Flutter Text Overflow while adding long text.
How to wrap text in flutter',
style:TextStyle(fontSize: 20),
),
)
61. The LinearProgressindicator widget is a material design for linear progress indicator.
LinearProgressindicator(
value: controller.value,
semanticsLabel:'Linear progress indicator',
)
62. A checkbox and a list tile are combined in the widget known as CheckboxListTile.
In addition to the title, subtitle, and icon, it lets you define a checkbox.
CheckboxListTile(
value: _isChecked,
onChanged: (bool value) {
setState(() {
_isChecked = value;
});
},
)
63. A list that scrolls down each page is called PageView.
PageView(
children: [
Container(
color: Colors.pink,
child: Center(
child: Text('Page 1'),
),
),
Container(
color: Colors.cyan,
child: Center(
child: Text('Page 2'),
),
),
],
)