How to use Functions of another File in Dart / Flutter?
I have a Flutter app where I'm using the flutter_web_view package. I'm using it over several different files and would love to create its own file and simply reference with the _launchwebview function anywhere in my app because there are several lines of code needed in order to make it work. I know how to reference files and pass information but not methods/functions. Here is the class code...
import 'package:flutter/material.dart';
import 'package:flutter_web_view/flutter_web_view.dart';
class ShopClass extends StatefulWidget {
@override
ShopClassState createState() => new ShopClassState();
}
class ShopClassState extends State<ShopClass> {
String _redirectedToUrl;
FlutterWebView flutterWebView = new FlutterWebView();
bool _isLoading = false;
@override
initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
Widget leading;
if (_isLoading) {
leading = new CircularProgressIndicator();
}
var columnItems = <Widget>[
new MaterialButton(
onPressed: launchWebViewExample, child: new Text("Launch"))
];
if (_redirectedToUrl != null) {
columnItems.add(new Text("Redirected to $_redirectedToUrl"));
}
var app = new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
leading: leading,
),
body: new Column(
children: columnItems,
),
),
);
return app;
}
void launchWebViewExample() {
if (flutterWebView.isLaunched) {
return;
}
flutterWebView.launch("https://apptreesoftware.com",
headers: {
"X-SOME-HEADER": "MyCustomHeader",
},
javaScriptEnabled: false,
toolbarActions: [
new ToolbarAction("Dismiss", 1),
new ToolbarAction("Reload", 2)
],
barColor: Colors.green,
tintColor: Colors.white);
flutterWebView.onToolbarAction.listen((identifier) {
switch (identifier) {
case 1:
flutterWebView.dismiss();
break;
case 2:
reload();
break;
}
});
flutterWebView.listenForRedirect("mobile://test.com", true);
flutterWebView.onWebViewDidStartLoading.listen((url) {
setState(() => _isLoading = true);
});
flutterWebView.onWebViewDidLoad.listen((url) {
setState(() => _isLoading = false);
});
flutterWebView.onRedirect.listen((url) {
flutterWebView.dismiss();
setState(() => _redirectedToUrl = url);
});
}
void reload() {
flutterWebView.load(
"https://google.com",
headers: {
"X-SOME-HEADER": "MyCustomHeader",
},
);
}
}
How can I use launchWebViewExample
in another class?
Solution 1:
You can write a file with just that function, like:
test.dart
void launchWebView () {
print("1234");
}
and then import that file like this:
main.dart
import "test.dart";
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
launchWebView();
It is not really clean, but you can do that. Alternatively you can use a class with a static method like:
class test {
static void foo() {
print("1234");
}
}
and then in your code invoke it like that (after the import):
test.foo();
Solution 2:
Or you can just declare all your functions (helpers) inside a class and pass them as an argument to other class.
//The class which contains your functions
class HelperFunction{
//Define your method
void launchWebView () {
print("1234");
}
//Pass that function to a class
MyHomePage(launchWebView);
}
//The class which receives the function.
class MyHomePage extends StatefulWidget{
//Retrieve the function and store it to a variable of type Function.
final Function launchWebView;
MyHomePage(this.launchWebView);
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
//Access that function in State class using widget keyword.
widget.launchWebView();
}
}
Solution 3:
Use mixin
instead of global functions!
Why does this happen?
I'm using it over several different files and would love to create its own file and reference with the _launchwebview function anywhere in my app because there are several lines of code needed in order to make it work.
Underscored methods are private to a given library. Thus, if we define _launchwebview
in one file, that function is in a mini-library (Source). So, the method will only be accessible within that file. I explored how to expose private methods across files, but found the solution messy. I thus think the question would be better answered using public functions. The problem is implementing a shared function within different classes rather than simply providing access.
I've chosen to add this solution for this particular question since the method (launching a web view) would be good to have implemented within every appropriate Widget
class. Note that extension methods could also work in this case, but Flutter prefers composition over inheritance.
If we want to move a public, i.e. non-underscored method, to a different class without copy-pasting, we could try several outlined approaches. I have detailed the drawbacks of the existing options below.
Hacky solutions
- Using the
part
directive enables us to copy the source of one file with a private implementation and use it in another file. But this is discouraged because the technique increases the binary size, goes against the Effective Dart usage guide, and is clearly a code smell because we are copy-pasting the same code. - Using global functions doesn't follow Object Oriented programming. Global state breaks the Encapsulation principle. OOP is the best paradigm to use within Dart apps because of the way the language is designed (classes). The top answer recommends global functions, however, this should be a last resort given the powerful language capabilities of Dart.
- Static functions break encapsulation and the Open-Closed principle. They are hard to integrate with state management solutions because we track the state within instance method contexts. For example, integrating
provider
and other packages likeGetX
. - Defining a
Function
as a property of a class can lead to subtle bugs further down the line. For example, we could assign any function to this property because there is no function signature type checking. Furthermore, this is not a scalable solution with code duplications.
Solution: Mixins
Dart has inbuilt support for optionally adding functions to a class when we want to reduce duplicated code but avoid extending the whole class (Source). The mixin
keyword enables this by mixing a class with some specific logic. We can restrict the mixin
to a specific subclass with on
if needed.
Code example
LaunchWebView.dart
mixin LaunchWebView on StatelessWidget { // you can also constrain the mixin to specific classes using on in this line.
void launchWebView() {
// Add web view logic here. We can add variables to the mixin itself as well.
}
}
Usage
class ExampleClass extends StatelessWidget with LaunchWebView {
Widget build(BuildContext context) {
....
}
void testFunction() {
// We now have access to launchWebView().
launchWebView();
}
}
Solution 4:
You can do that in different ways:
1. Global function:
Define your function in a file, say global.dart
:
void func() => print('Hello');
To use it in any file, just call:
func();
2. Static function in a class:
Create a class, say Foo
and define your function in it:
class Foo {
static void func() => print('Hello');
}
To use it in any file, just call
Foo.func();
3. Use mixin:
-
If you want to use the function in any class:
Create a mixin, say
Bar
:mixin Bar { void func() => print('Hello'); }
To use it in a class, just use
with
keyword followed by mixin.class Baz with Bar { void main() => func(); }
-
If you want to restrict the mixin from being used with any class:
class Foo {}
Create a mixin, say
Bar
which is onFoo
.mixin Bar on Foo { void func() => print('Hello'); }
To use
Bar
mixin we need to extendFoo
class because this is what it is on.class Baz extends Foo with Bar { void main() => func(); }