Use raw string
A raw string can be used to avoid escaping only backslashes and dollars.
Do
var s = r'This is demo string \ and $';
Don't
var s = 'This is demo string \\ and \$';
When use relative and absolute imports together then It is possible to create confusion when the same class gets imported from two different ways. To avoid this case we should use a relative path in the lib/ folder.
Do
import '../../../utils/dialog_utils.dart';
Don't
import 'package:demo/src/utils/dialog_utils.dart';
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.getItems(),
api.getStuff()
]
);
Flexible(
child: GridView.count(
crossAxisCount: (orientation == Orientaation.portrait) ? 2 : 3,
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
padding: const EdgeInsets.all(4.0),
childAspectRatio: (orientation == Orientaation.portrait) ? 1.0 : 1.3,
children: someList.map(
(catData) => aListItemWidget(catData)
).toList()
)
);
Widget to the list of children, you will need to change the height of the Sizedbox whenever you add a widget.
Don't
SizedBox(
height: 20,
child: Column(
children: [
Text(Hey),
Text(You)
]
)
)
Do
Column(
mainAxisSize: MainAxisSize.min,
child: Column(
children: [
Text(Hey),
Text(You)
]
)
)
You can use the print0 function to view it in the system console. If your output is too much, then Android sometimes discards some log lines. To avoid this, you can use debugPrint().
You can also log your print calls to disk if you're doing long-term or background work.
Just wrap the widget with the Theme Widget and pass the ThemeData().
Theme(
data: ThemeData(...),
child: TextFormField(
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'What do people call you ?',
labelText: 'Name *',
)
validator: (value) {
return value!.contains('@') ? 'Do not use the @ char' : null;
}
)
)
allprojects {
repositories {
google()
mavenCentral()
}
tasks.withType(JavaCompile).configureEach {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
}
}
}
initialSettings: InAppWebViewSettings(contentBlockers: [
ContentBlocker(
trigger: ContentBlockerTrigger(
urlFilter: ".*",
resourceType: [
ContentBlockerTriggerResourceType.IMAGE,
ContentBlockerTriggerResourceType.STYLE_SHEET
],
unlessDomain: ["example.com", "github.com", "pub.dev"]
),
action: ContentBlockerAction(
type: ContentBlockerActionType.BLOCK
)
)
]),
For deeper trigger customization, you can use the other properties of ContentBlockerTrigger :
initialSettings: InAppWebViewSettings(contentBlockers: [
ContentBlocker(
trigger: ContentBlockerTrigger(
urlFilter: "https://flutter.dev/.*",
),
action: ContentBlockerAction(
type: ContentBlockerActionType.CSS_DISPLAY_NONE,
selector: '.notification, .media, #developer-story'
)
)
]),
Valid types are:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb &&
kDebugMode &&
defaultTargetPlatform == TargetPlatform.android) {
await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);
}
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey webViewKey = GlobalKey();
// list of Ad URL filters to be used to block ads loading.
final adUrlFilters = [
".*.doubleclick.net/.*",
".*.ads.pubmatic.com/.*",
".*.googlesyndication.com/.*",
".*.google-analytics.com/.*",
".*.adservice.google.*/.*",
".*.adbrite.com/.*",
".*.exponential.com/.*",
".*.quantserve.com/.*",
".*.scorecardresearch.com/.*",
".*.zedo.com/.*",
".*.adsafeprotected.com/.*",
".*.teads.tv/.*",
".*.outbrain.com/.*"
];
final List<ContentBlocker> contentBlockers = [];
var contentBlockerEnabled = true;
InAppWebViewController? webViewController;
@override
void initState() {
super.initState();
// for each Ad URL filter, add a Content Blocker to block its loading.
for (final adUrlFilter in adUrlFilters) {
contentBlockers.add(ContentBlocker(
trigger: ContentBlockerTrigger(
urlFilter: adUrlFilter,
),
action: ContentBlockerAction(
type: ContentBlockerActionType.BLOCK,
)));
}
// apply the "display: none" style to some HTML elements
contentBlockers.add(ContentBlocker(
trigger: ContentBlockerTrigger(
urlFilter: ".*",
),
action: ContentBlockerAction(
type: ContentBlockerActionType.CSS_DISPLAY_NONE,
selector: ".banner, .banners, .ads, .ad, .advert")));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Ads Content Blocker"),
actions: [
TextButton(
onPressed: () async {
contentBlockerEnabled = !contentBlockerEnabled;
if (contentBlockerEnabled) {
await webViewController?.setSettings(
settings: InAppWebViewSettings(
contentBlockers: contentBlockers));
} else {
await webViewController?.setSettings(
settings: InAppWebViewSettings(contentBlockers: []));
}
webViewController?.reload();
setState(() {});
},
style: TextButton.styleFrom(foregroundColor: Colors.white),
child: Text(contentBlockerEnabled ? 'Disable' : 'Enable'),
)
],
),
body: SafeArea(
child: Column(children: <Widget>[
Expanded(
child: Stack(
children: [
InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri('https://www.tomshardware.com/')),
initialSettings:
InAppWebViewSettings(contentBlockers: contentBlockers),
onWebViewCreated: (controller) {
webViewController = controller;
},
),
],
),
),
])));
}
}
Do
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: const [
Widget(),
Widget(),
Widget()
]
)
);
}
Don't
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
WidgetFunction(),
WidgetFunction(),
WidgetFunction()
]
)
);
}
Conclusion: Extracting widgets to a method is considered as a Flutter anti-pattern, because when Flutter rebuilds widget tree, it calls the function all the time, making more processor time for the operations while widgets they will be rendered once and will not update themselves.