Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

docs.flutter.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.

Learn more
Flutter for Xamarin.Forms developers

Don't miss ourDecember livestream, with updates on Flutter and live Q&A!

Flutter for Xamarin.Forms developers

Learn how to apply Xamarin.Forms developer knowledge when building Flutter apps.

This document is meant for Xamarin.Forms developers looking to apply their existing knowledge to build mobile apps with Flutter. If you understand the fundamentals of the Xamarin.Forms framework, then you can use this document as a jump start to Flutter development.

Your Android and iOS knowledge and skill set are valuable when building with Flutter, because Flutter relies on the native operating system configurations, similar to how you would configure your native Xamarin.Forms projects. The Flutter Frameworks is also similar to how you create a single UI, that is used on multiple platforms.

This document can be used as a cookbook by jumping around and finding questions that are most relevant to your needs.

Project setup

#

How does the app start?

#

For each platform in Xamarin.Forms, you call theLoadApplication method, which creates a new application and starts your app.

csharp
LoadApplication(new App());

In Flutter, the default main entry point ismain where you load your Flutter app.

dart
voidmain(){runApp(constMyApp());}

In Xamarin.Forms, you assign aPage to theMainPage property in theApplication class.

csharp
public class App : Application{    public App()    {        MainPage = new ContentPage        {            Content = new Label            {                Text = "Hello World",                HorizontalOptions = LayoutOptions.Center,                VerticalOptions = LayoutOptions.Center            }        };    }}

In Flutter, "everything is a widget", even the application itself. The following example showsMyApp, a simple applicationWidget.

dart
classMyAppextendsStatelessWidget{/// This widget is the root of your application.constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstCenter(child:Text('Hello World!',textDirection:TextDirection.ltr),);}}

How do you create a page?

#

Xamarin.Forms has many types of pages;ContentPage is the most common. In Flutter, you specify an application widget that holds your root page. You can use aMaterialApp widget, which supportsMaterial Design, or you can use aCupertinoApp widget, which supports an iOS-style app, or you can use the lower levelWidgetsApp, which you can customize in any way you want.

The following code defines the home page, a stateful widget. In Flutter, all widgets are immutable, but two types of widgets are supported:Stateful andStateless. Examples of a stateless widget are titles, icons, or images.

The following example usesMaterialApp, which holds its root page in thehome property.

dart
classMyAppextendsStatelessWidget{/// This widget is the root of your application.constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Flutter Demo',home:MyHomePage(title:'Flutter Demo Home Page'),);}}

From here, your actual first page is anotherWidget, in which you create your state.

AStateful widget, such asMyHomePage below, consists of two parts. The first part, which is itself immutable, creates aState object that holds the state of the object. TheState object persists over the life of the widget.

dart
classMyHomePageextendsStatefulWidget{constMyHomePage({super.key,requiredthis.title});finalStringtitle;@overrideState<MyHomePage>createState()=>_MyHomePageState();}

TheState object implements thebuild() method for the stateful widget.

When the state of the widget tree changes, callsetState(), which triggers a build of that portion of the UI. Make sure to callsetState() only when necessary, and only on the part of the widget tree that has changed, or it can result in poor UI performance.

dart
class_MyHomePageStateextendsState<MyHomePage>{int_counter=0;void_incrementCounter(){setState((){_counter++;});}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(// Take the value from the MyHomePage object that was created by// the App.build method, and use it to set the appbar title.title:Text(widget.title),),body:Center(// Center is a layout widget. It takes a single child and positions it// in the middle of the parent.child:Column(mainAxisAlignment:MainAxisAlignment.center,children:<Widget>[constText('You have pushed the button this many times:'),Text('$_counter',style:Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton:FloatingActionButton(onPressed:_incrementCounter,tooltip:'Increment',child:constIcon(Icons.add),),);}}

In Flutter, the UI (also known as widget tree), is immutable, meaning you can't change its state once it's built. You change fields in yourState class, then callsetState() to rebuild the entire widget tree again.

This way of generating UI is different from Xamarin.Forms, but there are many benefits to this approach.

Views

#

What is the equivalent of a Page or Element in Flutter?

#

ContentPage,TabbedPage,FlyoutPage are all types of pages you might use in a Xamarin.Forms application. These pages would then holdElements to display the various controls. In Xamarin.Forms anEntry orButton are examples of anElement.

In Flutter, almost everything is a widget. APage, called aRoute in Flutter, is a widget. Buttons, progress bars, and animation controllers are all widgets. When building a route, you create a widget tree.

Flutter includes theMaterial Components library. These are widgets that implement theMaterial Design guidelines. Material Design is a flexible design systemoptimized for all platforms, including iOS.

But Flutter is flexible and expressive enough to implement any design language. For example, on iOS, you can use theCupertino widgets to produce an interface that looks likeApple's iOS design language.

How do I update widgets?

#

In Xamarin.Forms, eachPage orElement is a stateful class, that has properties and methods. You update yourElement by updating a property, and this is propagated down to the native control.

In Flutter,Widgets are immutable and you can't directly update them by changing a property, instead you have to work with the widget's state.

This is where the concept of Stateful vs Stateless widgets comes from. AStatelessWidget is just what it sounds like— a widget with no state information.

StatelessWidgets are useful when the part of the user interface you are describing doesn't depend on anything other than the configuration information in the object.

For example, in Xamarin.Forms, this is similar to placing anImage with your logo. The logo is not going to change during runtime, so use aStatelessWidget in Flutter.

If you want to dynamically change the UI based on data received after making an HTTP call or a user interaction, then you have to work withStatefulWidget and tell the Flutter framework that the widget'sState has been updated, so it can update that widget.

The important thing to note here is at the core both stateless and stateful widgets behave the same. They rebuild every frame, the difference is theStatefulWidget has aState object that stores state data across frames and restores it.

If you are in doubt, then always remember this rule: if a widget changes (because of user interactions, for example) it's stateful. However, if a widget reacts to change, the containing parent widget can still be stateless if it doesn't itself react to change.

The following example shows how to use aStatelessWidget. A commonStatelessWidget is theText widget. If you look at the implementation of theText widget you'll find it subclassesStatelessWidget.

dart
constText('I like Flutter!',style:TextStyle(fontWeight:FontWeight.bold),);

As you can see, theText widget has no state information associated with it, it renders what is passed in its constructors and nothing more.

But, what if you want to make "I Like Flutter" change dynamically, for example, when clicking aFloatingActionButton?

To achieve this, wrap theText widget in aStatefulWidget and update it when the user clicks the button, as shown in the following example:

dart
import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{/// Default placeholder textStringtextToShow='I Like Flutter';void_updateText(){setState((){// Update the texttextToShow='Flutter is Awesome!';});}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:Center(child:Text(textToShow)),floatingActionButton:FloatingActionButton(onPressed:_updateText,tooltip:'Update Text',child:constIcon(Icons.update),),);}}

How do I lay out my widgets? What is the equivalent of an XAML file?

#

In Xamarin.Forms, most developers write layouts in XAML, though sometimes in C#. In Flutter, you write your layouts with a widget tree in code.

The following example shows how to display a simple widget with padding:

dart
@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:Center(child:ElevatedButton(style:ElevatedButton.styleFrom(padding:constEdgeInsets.only(left:20,right:30),),onPressed:(){},child:constText('Hello'),),),);}

You can view the layouts that Flutter has to offer in thewidget catalog.

How do I add or remove an Element from my layout?

#

In Xamarin.Forms, you had to remove or add anElement in code. This involved either setting theContent property or callingAdd() orRemove() if it was a list.

In Flutter, because widgets are immutable there is no direct equivalent. Instead, you can pass a function to the parent that returns a widget, and control that child's creation with a boolean flag.

The following example shows how to toggle between two widgets when the user clicks theFloatingActionButton:

dart
classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{/// Default value for togglebooltoggle=true;void_toggle(){setState((){toggle=!toggle;});}Widget_getToggleChild(){if(toggle){returnconstText('Toggle One');}returnCupertinoButton(onPressed:(){},child:constText('Toggle Two'));}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:Center(child:_getToggleChild()),floatingActionButton:FloatingActionButton(onPressed:_toggle,tooltip:'Update Text',child:constIcon(Icons.update),),);}}

How do I animate a widget?

#

In Xamarin.Forms, you create simple animations using ViewExtensions that include methods such asFadeTo andTranslateTo. You would use these methods on a view to perform the required animations.

xml
<Image Source="{Binding MyImage}" x:Name="myImage" />

Then in code behind, or a behavior, this would fade in the image, over a 1-second period.

csharp
myImage.FadeTo(0, 1000);

In Flutter, you animate widgets using the animation library by wrapping widgets inside an animated widget. Use anAnimationController, which is anAnimation<double> that can pause, seek, stop and reverse the animation. It requires aTicker that signals when vsync happens, and produces a linear interpolation between 0 and 1 on each frame while it's running. You then create one or moreAnimations and attach them to the controller.

For example, you might useCurvedAnimation to implement an animation along an interpolated curve. In this sense, the controller is the "master" source of the animation progress and theCurvedAnimation computes the curve that replaces the controller's default linear motion. Like widgets, animations in Flutter work with composition.

When building the widget tree, you assign theAnimation to an animated property of a widget, such as the opacity of aFadeTransition, and tell the controller to start the animation.

The following example shows how to write aFadeTransition that fades the widget into a logo when you press theFloatingActionButton:

dart
import'package:flutter/material.dart';voidmain(){runApp(constFadeAppTest());}classFadeAppTestextendsStatelessWidget{/// This widget is the root of your application.constFadeAppTest({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Fade Demo',home:MyFadeTest(title:'Fade Demo'),);}}classMyFadeTestextendsStatefulWidget{constMyFadeTest({super.key,requiredthis.title});finalStringtitle;@overrideState<MyFadeTest>createState()=>_MyFadeTest();}class_MyFadeTestextendsState<MyFadeTest>withTickerProviderStateMixin{latefinalAnimationControllercontroller;latefinalCurvedAnimationcurve;@overridevoidinitState(){super.initState();controller=AnimationController(duration:constDuration(milliseconds:2000),vsync:this,);curve=CurvedAnimation(parent:controller,curve:Curves.easeIn);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text(widget.title)),body:Center(child:FadeTransition(opacity:curve,child:constFlutterLogo(size:100),),),floatingActionButton:FloatingActionButton(onPressed:(){controller.forward();},tooltip:'Fade',child:constIcon(Icons.brush),),);}}

For more information, seeAnimation & Motion widgets, theAnimations tutorial, and theAnimations overview.

How do I draw/paint on the screen?

#

Xamarin.Forms never had a built-in way to draw directly on the screen. Many would use SkiaSharp, if they needed a custom image drawn. In Flutter, you have direct access to the Skia Canvas and can easily draw on screen.

Flutter has two classes that help you draw to the canvas:CustomPaint andCustomPainter, the latter of which implements your algorithm to draw to the canvas.

To learn how to implement a signature painter in Flutter, see Collin's answer onCustom Paint.

dart
import'package:flutter/material.dart';voidmain(){runApp(constMaterialApp(home:DemoApp()));}classDemoAppextendsStatelessWidget{constDemoApp({super.key});@overrideWidgetbuild(BuildContextcontext)=>constScaffold(body:Signature());}classSignatureextendsStatefulWidget{constSignature({super.key});@overrideSignatureStatecreateState()=>SignatureState();}classSignatureStateextendsState<Signature>{List<Offset?>_points=<Offset?>[];void_onPanUpdate(DragUpdateDetailsdetails){setState((){finalRenderBoxreferenceBox=context.findRenderObject()asRenderBox;finalOffsetlocalPosition=referenceBox.globalToLocal(details.globalPosition,);_points=List.from(_points)..add(localPosition);});}@overrideWidgetbuild(BuildContextcontext){returnGestureDetector(onPanUpdate:_onPanUpdate,onPanEnd:(details)=>_points.add(null),child:CustomPaint(painter:SignaturePainter(_points),size:Size.infinite,),);}}classSignaturePainterextendsCustomPainter{constSignaturePainter(this.points);finalList<Offset?>points;@overridevoidpaint(Canvascanvas,Sizesize){finalPaintpaint=Paint()..color=Colors.black..strokeCap=StrokeCap.round..strokeWidth=5;for(inti=0;i<points.length-1;i++){if(points[i]!=null&&points[i+1]!=null){canvas.drawLine(points[i]!,points[i+1]!,paint);}}}@overrideboolshouldRepaint(SignaturePainteroldDelegate)=>oldDelegate.points!=points;}

Where is the widget's opacity?

#

On Xamarin.Forms, allVisualElements have an Opacity. In Flutter, you need to wrap a widget in anOpacity widget to accomplish this.

How do I build custom widgets?

#

In Xamarin.Forms, you typically subclassVisualElement, or use a pre-existingVisualElement, to override and implement methods that achieve the desired behavior.

In Flutter, build a custom widget bycomposing smaller widgets (instead of extending them). It is somewhat similar to implementing a custom control based off aGrid with numerousVisualElements added in, while extending with custom logic.

For example, how do you build aCustomButton that takes a label in the constructor? Create a CustomButton that composes aElevatedButton with a label, rather than by extendingElevatedButton:

dart
classCustomButtonextendsStatelessWidget{constCustomButton(this.label,{super.key});finalStringlabel;@overrideWidgetbuild(BuildContextcontext){returnElevatedButton(onPressed:(){},child:Text(label));}}

Then useCustomButton, just as you'd use any other Flutter widget:

dart
@overrideWidgetbuild(BuildContextcontext){returnconstCenter(child:CustomButton('Hello'));}

Navigation

#

How do I navigate between pages?

#

In Xamarin.Forms, theNavigationPage class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards.

Flutter has a similar implementation, using aNavigator andRoutes. ARoute is an abstraction for aPage of an app, and aNavigator is awidget that manages routes.

A route roughly maps to aPage. The navigator works in a similar way to the Xamarin.FormsNavigationPage, in that it canpush() andpop() routes depending on whether you want to navigate to, or back from, a view.

To navigate between pages, you have a couple options:

  • Specify aMap of route names. (MaterialApp)
  • Directly navigate to a route. (WidgetsApp)

The following example builds aMap.

dart
voidmain(){runApp(MaterialApp(home:constMyAppHome(),// becomes the route named '/'routes:<String,WidgetBuilder>{'/a':(context)=>constMyPage(title:'page A'),'/b':(context)=>constMyPage(title:'page B'),'/c':(context)=>constMyPage(title:'page C'),},),);}

Navigate to a route by pushing its name to theNavigator.

dart
Navigator.of(context).pushNamed('/b');

TheNavigator is a stack that manages your app's routes. Pushing a route to the stack moves to that route. Popping a route from the stack, returns to the previous route. This is done by awaiting on theFuture returned bypush().

async/await is very similar to the .NET implementation and is explained in more detail inAsync UI.

For example, to start alocation route that lets the user select their location, you might do the following:

dart
Object?coordinates=awaitNavigator.of(context).pushNamed('/location');

And then, inside your 'location' route, once the user has selected their location, pop the stack with the result:

dart
Navigator.of(context).pop({'lat':43.821757,'long':-79.226392});

How do I navigate to another app?

#

In Xamarin.Forms, to send the user to another application, you use a specific URI scheme, usingDevice.OpenUrl("mailto://").

To implement this functionality in Flutter, create a native platform integration, or use anexisting plugin, such asurl_launcher, available with many other packages onpub.dev.

Async UI

#

What is the equivalent of Device.BeginOnMainThread() in Flutter?

#

Dart has a single-threaded execution model, with support forIsolates (a way to run Dart codes on another thread), an event loop, and asynchronous programming. Unless you spawn anIsolate, your Dart code runs in the main UI thread and is driven by an event loop.

Dart's single-threaded model doesn't mean you need to run everything as a blocking operation that causes the UI to freeze. Much like Xamarin.Forms, you need to keep the UI thread free. You would useasync/await to perform tasks, where you must wait for the response.

In Flutter, use the asynchronous facilities that the Dart language provides, also namedasync/await, to perform asynchronous work. This is very similar to C# and should be very easy to use for any Xamarin.Forms developer.

For example, you can run network code without causing the UI to hang by usingasync/await and letting Dart do the heavy lifting:

dart
Future<void>loadData()async{finalUridataURL=Uri.parse('https://jsonplaceholder.typicode.com/posts');finalhttp.Responseresponse=awaithttp.get(dataURL);setState((){data=(jsonDecode(response.body)asList).cast<Map<String,Object?>>();});}

Once the awaited network call is done, update the UI by callingsetState(), which triggers a rebuild of the widget subtree and updates the data.

The following example loads data asynchronously and displays it in aListView:

dart
import'dart:convert';import'package:flutter/material.dart';import'package:http/http.dart'ashttp;voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{List<Map<String,Object?>>data=[];@overridevoidinitState(){super.initState();loadData();}Future<void>loadData()async{finalUridataURL=Uri.parse('https://jsonplaceholder.typicode.com/posts');finalhttp.Responseresponse=awaithttp.get(dataURL);setState((){data=(jsonDecode(response.body)asList).cast<Map<String,Object?>>();});}WidgetgetRow(intindex){returnPadding(padding:constEdgeInsets.all(10),child:Text('Row${data[index]['title']}'),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView.builder(itemCount:data.length,itemBuilder:(context,index){returngetRow(index);},),);}}

Refer to the next section for more information on doing work in the background, and how Flutter differs from Android.

How do you move work to a background thread?

#

Since Flutter is single threaded and runs an event loop, you don't have to worry about thread management or spawning background threads. This is very similar to Xamarin.Forms. If you're doing I/O-bound work, such as disk access or a network call, then you can safely useasync/await and you're all set.

If, on the other hand, you need to do computationally intensive work that keeps the CPU busy, you want to move it to anIsolate to avoid blocking the event loop, like you would keepany sort of work out of the main thread. This is similar to when you move things to a different thread viaTask.Run() in Xamarin.Forms.

For I/O-bound work, declare the function as anasync function, andawait on long-running tasks inside the function:

dart
Future<void>loadData()async{finalUridataURL=Uri.parse('https://jsonplaceholder.typicode.com/posts');finalhttp.Responseresponse=awaithttp.get(dataURL);setState((){data=(jsonDecode(response.body)asList).cast<Map<String,Object?>>();});}

This is how you would typically do network or database calls, which are both I/O operations.

However, there are times when you might be processing a large amount of data and your UI hangs. In Flutter, useIsolates to take advantage of multiple CPU cores to do long-running or computationally intensive tasks.

Isolates are separate execution threads that do not share any memory with the main execution memory heap. This is a difference betweenTask.Run(). This means you can't access variables from the main thread, or update your UI by callingsetState().

The following example shows, in a simple isolate, how to share data back to the main thread to update the UI.

dart
Future<void>loadData()async{finalReceivePortreceivePort=ReceivePort();awaitIsolate.spawn(dataLoader,receivePort.sendPort);// The 'echo' isolate sends its SendPort as the first messagefinalSendPortsendPort=awaitreceivePort.firstasSendPort;finalList<Map<String,dynamic>>msg=awaitsendReceive(sendPort,'https://jsonplaceholder.typicode.com/posts',);setState((){data=msg;});}// The entry point for the isolatestaticFuture<void>dataLoader(SendPortsendPort)async{// Open the ReceivePort for incoming messages.finalReceivePortport=ReceivePort();// Notify any other isolates what port this isolate listens to.sendPort.send(port.sendPort);awaitfor(finaldynamicmsginport){finalStringurl=msg[0]asString;finalSendPortreplyTo=msg[1]asSendPort;finalUridataURL=Uri.parse(url);finalhttp.Responseresponse=awaithttp.get(dataURL);// Lots of JSON to parsereplyTo.send(jsonDecode(response.body)asList<Map<String,dynamic>>);}}Future<List<Map<String,dynamic>>>sendReceive(SendPortport,Stringmsg){finalReceivePortresponse=ReceivePort();port.send(<dynamic>[msg,response.sendPort]);returnresponse.firstasFuture<List<Map<String,dynamic>>>;}

Here,dataLoader() is theIsolate that runs in its own separate execution thread. In the isolate, you can perform more CPU intensive processing (parsing a big JSON, for example), or perform computationally intensive math, such as encryption or signal processing.

You can run the full example below:

dart
import'dart:async';import'dart:convert';import'dart:isolate';import'package:flutter/material.dart';import'package:http/http.dart'ashttp;voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{List<Map<String,Object?>>data=[];@overridevoidinitState(){super.initState();loadData();}boolgetshowLoadingDialog=>data.isEmpty;Future<void>loadData()async{finalReceivePortreceivePort=ReceivePort();awaitIsolate.spawn(dataLoader,receivePort.sendPort);// The 'echo' isolate sends its SendPort as the first messagefinalSendPortsendPort=awaitreceivePort.firstasSendPort;finalList<Map<String,dynamic>>msg=awaitsendReceive(sendPort,'https://jsonplaceholder.typicode.com/posts',);setState((){data=msg;});}// The entry point for the isolatestaticFuture<void>dataLoader(SendPortsendPort)async{// Open the ReceivePort for incoming messages.finalReceivePortport=ReceivePort();// Notify any other isolates what port this isolate listens to.sendPort.send(port.sendPort);awaitfor(finaldynamicmsginport){finalStringurl=msg[0]asString;finalSendPortreplyTo=msg[1]asSendPort;finalUridataURL=Uri.parse(url);finalhttp.Responseresponse=awaithttp.get(dataURL);// Lots of JSON to parsereplyTo.send(jsonDecode(response.body)asList<Map<String,dynamic>>);}}Future<List<Map<String,dynamic>>>sendReceive(SendPortport,Stringmsg){finalReceivePortresponse=ReceivePort();port.send(<dynamic>[msg,response.sendPort]);returnresponse.firstasFuture<List<Map<String,dynamic>>>;}WidgetgetBody(){if(showLoadingDialog){returngetProgressDialog();}returngetListView();}WidgetgetProgressDialog(){returnconstCenter(child:CircularProgressIndicator());}ListViewgetListView(){returnListView.builder(itemCount:data.length,itemBuilder:(context,index){returngetRow(index);},);}WidgetgetRow(intindex){returnPadding(padding:constEdgeInsets.all(10),child:Text('Row${data[index]['title']}'),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:getBody(),);}}

How do I make network requests?

#

In Xamarin.Forms you would useHttpClient. Making a network call in Flutter is easy when you use the popularhttp package. This abstracts away a lot of the networking that you might normally implement yourself, making it simple to make network calls.

To use thehttp package, add it to your dependencies inpubspec.yaml:

yaml
dependencies:http:^1.4.0

To make a network request, callawait on theasync functionhttp.get():

dart
Future<void>loadData()async{finalUridataURL=Uri.parse('https://jsonplaceholder.typicode.com/posts');finalhttp.Responseresponse=awaithttp.get(dataURL);setState((){data=(jsonDecode(response.body)asList).cast<Map<String,Object?>>();});}

How do I show the progress for a long-running task?

#

In Xamarin.Forms you would typically create a loading indicator, either directly in XAML or through a 3rd party plugin such as AcrDialogs.

In Flutter, use aProgressIndicator widget. Show the progress programmatically by controlling when it's rendered through a boolean flag. Tell Flutter to update its state before your long-running task starts, and hide it after it ends.

In the example below, the build function is separated into three different functions. IfshowLoadingDialog istrue (whenwidgets.length == 0), then render theProgressIndicator. Otherwise, render theListView with the data returned from a network call.

dart
import'dart:async';import'dart:convert';import'package:flutter/material.dart';import'package:http/http.dart'ashttp;voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{List<Map<String,Object?>>data=[];@overridevoidinitState(){super.initState();loadData();}boolgetshowLoadingDialog=>data.isEmpty;Future<void>loadData()async{finalUridataURL=Uri.parse('https://jsonplaceholder.typicode.com/posts');finalhttp.Responseresponse=awaithttp.get(dataURL);setState((){data=(jsonDecode(response.body)asList).cast<Map<String,Object?>>();});}WidgetgetBody(){if(showLoadingDialog){returngetProgressDialog();}returngetListView();}WidgetgetProgressDialog(){returnconstCenter(child:CircularProgressIndicator());}ListViewgetListView(){returnListView.builder(itemCount:data.length,itemBuilder:(context,index){returngetRow(index);},);}WidgetgetRow(intindex){returnPadding(padding:constEdgeInsets.all(10),child:Text('Row${data[index]['title']}'),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:getBody(),);}}

Project structure & resources

#

Where do I store my image files?

#

Xamarin.Forms has no platform independent way of storing images, you had to place images in the iOSxcasset folder, or on Android in the variousdrawable folders.

While Android and iOS treat resources and assets as distinct items, Flutter apps have only assets. All resources that would live in theResources/drawable-* folders on Android, are placed in an assets' folder for Flutter.

Flutter follows a simple density-based format like iOS. Assets might be1.0x,2.0x,3.0x, or any other multiplier. Flutter doesn't havedps but there are logical pixels, which are basically the same as device-independent pixels. Flutter'sdevicePixelRatio expresses the ratio of physical pixels in a single logical pixel.

The equivalent to Android's density buckets are:

Android density qualifierFlutter pixel ratio
ldpi0.75x
mdpi1.0x
hdpi1.5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x

Assets are located in any arbitrary folder— Flutter has no predefined folder structure. You declare the assets (with location) in thepubspec.yaml file, and Flutter picks them up.

To add a new image asset calledmy_icon.png to our Flutter project, for example, and deciding that it should live in a folder we arbitrarily calledimages, you would put the base image (1.0x) in theimages folder, and all the other variants in sub-folders called with the appropriate ratio multiplier:

images/my_icon.png       // Base: 1.0x imageimages/2.0x/my_icon.png  // 2.0x imageimages/3.0x/my_icon.png  // 3.0x image

Next, you'll need to declare these images in yourpubspec.yaml file:

yaml
assets:-images/my_icon.png

You can directly access your images in anImage.asset widget:

dart
@overrideWidgetbuild(BuildContextcontext){returnImage.asset('images/my_icon.png');}

or usingAssetImage:

dart
@overrideWidgetbuild(BuildContextcontext){returnconstImage(image:AssetImage('images/my_image.png'));}

More detailed information can be found inAdding assets and images.

Where do I store strings? How do I handle localization?

#

Unlike .NET which hasresx files, Flutter doesn't currently have a dedicated system for handling strings. At the moment, the best practice is to declare your copy text in a class as static fields and access them from there. For example:

dart
classStrings{staticconstStringwelcomeMessage='Welcome To Flutter';}

You can access your strings as such:

dart
Text(Strings.welcomeMessage);

By default, Flutter only supports US English for its strings. If you need to add support for other languages, include theflutter_localizations package. You might also need to add Dart'sintl package to use i10n machinery, such as date/time formatting.

yaml
dependencies:flutter_localizations:sdk:flutterintl:any# Use version of intl from flutter_localizations.

To use theflutter_localizations package, specify thelocalizationsDelegates andsupportedLocales on the app widget:

dart
import'package:flutter_localizations/flutter_localizations.dart';classMyWidgetextendsStatelessWidget{constMyWidget({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(localizationsDelegates:<LocalizationsDelegate<dynamic>>[// Add app-specific localization delegate[s] hereGlobalMaterialLocalizations.delegate,GlobalWidgetsLocalizations.delegate,],supportedLocales:<Locale>[Locale('en','US'),// EnglishLocale('he','IL'),// Hebrew// ... other locales the app supports],);}}

The delegates contain the actual localized values, while thesupportedLocales defines which locales the app supports. The above example uses aMaterialApp, so it has both aGlobalWidgetsLocalizations for the base widgets localized values, and aMaterialWidgetsLocalizations for the Material widgets localizations. If you useWidgetsApp for your app, you don't need the latter. Note that these two delegates contain "default" values, but you'll need to provide one or more delegates for your own app's localizable copy, if you want those to be localized too.

When initialized, theWidgetsApp (orMaterialApp) creates aLocalizations widget for you, with the delegates you specify. The current locale for the device is always accessible from theLocalizations widget from the current context (in the form of aLocale object), or using theWindow.locale.

To access localized resources, use theLocalizations.of() method to access a specific localizations class that is provided by a given delegate. Use theintl_translation package to extract translatable copy toarb files for translating, and importing them back into the app for using them withintl.

For further details on internationalization and localization in Flutter, see theinternationalization guide, which has sample code with and without theintl package.

Where is my project file?

#

In Xamarin.Forms you will have acsproj file. The closest equivalent in Flutter is pubspec.yaml, which contains package dependencies and various project details. Similar to .NET Standard, files within the same directory are considered part of the project.

What is the equivalent of Nuget? How do I add dependencies?

#

In the .NET ecosystem, native Xamarin projects and Xamarin.Forms projects had access to Nuget and the built-in package management system. Flutter apps contain a native Android app, native iOS app and Flutter app.

In Android, you add dependencies by adding to your Gradle build script. In iOS, you add dependencies by adding to yourPodfile.

Flutter uses Dart's own build system, and the Pub package manager. The tools delegate the building of the native Android and iOS wrapper apps to the respective build systems.

In general, usepubspec.yaml to declare external dependencies to use in Flutter. A good place to find Flutter packages is onpub.dev.

Application lifecycle

#

How do I listen to application lifecycle events?

#

In Xamarin.Forms, you have anApplication that containsOnStart,OnResume andOnSleep. In Flutter, you can instead listen to similar lifecycle events by hooking into theWidgetsBinding observer and listening to thedidChangeAppLifecycleState() change event.

The observable lifecycle events are:

inactive

The application is in an inactive state and is not receiving user input. This event is iOS only.

paused

The application is not currently visible to the user, is not responding to user input, but is running in the background.

resumed

The application is visible and responding to user input.

suspending

The application is suspended momentarily. This event is Android only.

For more details on the meaning of these states, see theAppLifecycleStatus documentation.

Layouts

#

What is the equivalent of a StackLayout?

#

In Xamarin.Forms you can create aStackLayout with anOrientation of horizontal or vertical. Flutter has a similar approach, however you would use theRow orColumn widgets.

If you notice the two code samples are identical except theRow andColumn widget. The children are the same and this feature can be exploited to develop rich layouts that can change overtime with the same children.

dart
@overrideWidgetbuild(BuildContextcontext){returnconstRow(mainAxisAlignment:MainAxisAlignment.center,children:<Widget>[Text('Row One'),Text('Row Two'),Text('Row Three'),Text('Row Four'),],);}
dart
@overrideWidgetbuild(BuildContextcontext){returnconstColumn(mainAxisAlignment:MainAxisAlignment.center,children:<Widget>[Text('Column One'),Text('Column Two'),Text('Column Three'),Text('Column Four'),],);

What is the equivalent of a Grid?

#

The closest equivalent of aGrid would be aGridView. This is much more powerful than what you are used to in Xamarin.Forms. AGridView provides automatic scrolling when the content exceeds its viewable space.

dart
@overrideWidgetbuild(BuildContextcontext){returnGridView.count(// Create a grid with 2 columns. If you change the scrollDirection to// horizontal, this would produce 2 rows.crossAxisCount:2,// Generate 100 widgets that display their index in the list.children:List<Widget>.generate(100,(index){returnCenter(child:Text('Item$index',style:Theme.of(context).textTheme.headlineMedium,),);}),);}

You might have used aGrid in Xamarin.Forms to implement widgets that overlay other widgets. In Flutter, you accomplish this with theStack widget.

This sample creates two icons that overlap each other.

dart
@overrideWidgetbuild(BuildContextcontext){returnconstStack(children:<Widget>[Icon(Icons.add_box,size:24,color:Colors.black),Positioned(left:10,child:Icon(Icons.add_circle,size:24,color:Colors.black),),],);}

What is the equivalent of a ScrollView?

#

In Xamarin.Forms, aScrollView wraps around aVisualElement, and if the content is larger than the device screen, it scrolls.

In Flutter, the closest match is theSingleChildScrollView widget. You simply fill the Widget with the content that you want to be scrollable.

dart
@overrideWidgetbuild(BuildContextcontext){returnconstSingleChildScrollView(child:Text('Long Content'));}

If you have many items you want to wrap in a scroll, even of differentWidget types, you might want to use aListView. This might seem like overkill, but in Flutter this is far more optimized and less intensive than a Xamarin.FormsListView, which is backing on to platform specific controls.

dart
@overrideWidgetbuild(BuildContextcontext){returnListView(children:const<Widget>[Text('Row One'),Text('Row Two'),Text('Row Three'),Text('Row Four'),],);}

How do I handle landscape transitions in Flutter?

#

Landscape transitions can be handled automatically by setting theconfigChanges property in the AndroidManifest.xml:

xml
<activity android:configChanges="orientation|screenSize" />

Gesture detection and touch event handling

#

How do I add GestureRecognizers to a widget in Flutter?

#

In Xamarin.Forms,Elements might contain a click event you can attach to. Many elements also contain aCommand that is tied to this event. Alternatively you would use theTapGestureRecognizer. In Flutter there are two very similar ways:

  1. If the widget supports event detection, pass a function to it and handle it in the function. For example, the ElevatedButton has anonPressed parameter:

    dart
    @overrideWidgetbuild(BuildContextcontext){returnElevatedButton(onPressed:(){developer.log('click');},child:constText('Button'),);}
  2. If the widget doesn't support event detection, wrap the widget in aGestureDetector and pass a function to theonTap parameter.

    dart
    classSampleAppextendsStatelessWidget{constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:Center(child:GestureDetector(onTap:(){developer.log('tap');},child:constFlutterLogo(size:200),),),);}}

How do I handle other gestures on widgets?

#

In Xamarin.Forms you would add aGestureRecognizer to theView. You would normally be limited toTapGestureRecognizer,PinchGestureRecognizer,PanGestureRecognizer,SwipeGestureRecognizer,DragGestureRecognizer andDropGestureRecognizer unless you built your own.

In Flutter, using the GestureDetector, you can listen to a wide range of Gestures such as:

  • Tap
onTapDown

A pointer that might cause a tap has contacted the screen at a particular location.

onTapUp

A pointer that triggers a tap has stopped contacting the screen at a particular location.

onTap

A tap has occurred.

onTapCancel

The pointer that previously triggered theonTapDown won't cause a tap.

  • Double tap
onDoubleTap

The user tapped the screen at the same location twice in quick succession.

  • Long press
onLongPress

A pointer has remained in contact with the screen at the same location for a long period of time.

  • Vertical drag
onVerticalDragStart

A pointer has contacted the screen and might begin to move vertically.

onVerticalDragUpdate

A pointer in contact with the screen has moved further in the vertical direction.

onVerticalDragEnd

A pointer that was previously in contact with the screen and moving vertically is no longer in contact with the screen and was moving at a specific velocity when it stopped contacting the screen.

  • Horizontal drag
onHorizontalDragStart

A pointer has contacted the screen and might begin to move horizontally.

onHorizontalDragUpdate

A pointer in contact with the screen has moved further in the horizontal direction.

onHorizontalDragEnd

A pointer that was previously in contact with the screen and moving horizontally is no longer in contact with the screen and was moving at a specific velocity when it stopped contacting the screen.

The following example shows aGestureDetector that rotates the Flutter logo on a double tap:

dart
classRotatingFlutterDetectorextendsStatefulWidget{constRotatingFlutterDetector({super.key});@overrideState<RotatingFlutterDetector>createState()=>_RotatingFlutterDetectorState();}class_RotatingFlutterDetectorStateextendsState<RotatingFlutterDetector>withSingleTickerProviderStateMixin{latefinalAnimationControllercontroller;latefinalCurvedAnimationcurve;@overridevoidinitState(){super.initState();controller=AnimationController(duration:constDuration(milliseconds:2000),vsync:this,);curve=CurvedAnimation(parent:controller,curve:Curves.easeIn);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:Center(child:GestureDetector(onDoubleTap:(){if(controller.isCompleted){controller.reverse();}else{controller.forward();}},child:RotationTransition(turns:curve,child:constFlutterLogo(size:200),),),),);}}

Listviews and adapters

#

What is the equivalent to a ListView in Flutter?

#

The equivalent to aListView in Flutter is … aListView!

In a Xamarin.FormsListView, you create aViewCell and possibly aDataTemplateSelectorand pass it into theListView, which renders each row with what yourDataTemplateSelector orViewCell returns. However, you often have to make sure you turn on Cell Recycling otherwise you will run into memory issues and slow scrolling speeds.

Due to Flutter's immutable widget pattern, you pass a list of widgets to yourListView, and Flutter takes care of making sure that scrolling is fast and smooth.

dart
import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatelessWidget{constSampleAppPage({super.key});List<Widget>_getListData(){returnList<Widget>.generate(100,(index)=>Padding(padding:constEdgeInsets.all(10),child:Text('Row$index')),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView(children:_getListData()),);}}

How do I know which list item has been clicked?

#

In Xamarin.Forms, the ListView has anItemTapped method to find out which item was clicked. There are many other techniques you might have used such as checking whenSelectedItem orEventToCommand behaviors change.

In Flutter, use the touch handling provided by the passed-in widgets.

dart
import'dart:developer'asdeveloper;import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{List<Widget>_getListData(){returnList<Widget>.generate(100,(index)=>GestureDetector(onTap:(){developer.log('Row$index tapped');},child:Padding(padding:constEdgeInsets.all(10),child:Text('Row$index'),),),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView(children:_getListData()),);}}

How do I update a ListView dynamically?

#

In Xamarin.Forms, if you bound theItemsSource property to anObservableCollection, you would just update the list in your ViewModel. Alternatively, you could assign a newList to theItemSource property.

In Flutter, things work a little differently. If you update the list of widgets inside asetState() method, you would quickly see that your data did not change visually. This is because whensetState() is called, the Flutter rendering engine looks at the widget tree to see if anything has changed. When it gets to yourListView, it performs a== check, and determines that the twoListViews are the same. Nothing has changed, so no update is required.

For a simple way to update yourListView, create a newList inside ofsetState(), and copy the data from the old list to the new list. While this approach is simple, it is not recommended for large data sets, as shown in the next example.

dart
import'dart:developer'asdeveloper;import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{List<Widget>widgets=<Widget>[];@overridevoidinitState(){super.initState();for(inti=0;i<100;i++){widgets.add(getRow(i));}}WidgetgetRow(intindex){returnGestureDetector(onTap:(){setState((){widgets=List<Widget>.from(widgets);widgets.add(getRow(widgets.length));developer.log('Row$index');});},child:Padding(padding:constEdgeInsets.all(10),child:Text('Row$index'),),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView(children:widgets),);}}

The recommended, efficient, and effective way to build a list uses aListView.Builder. This method is great when you have a dynamic list or a list with very large amounts of data. This is essentially the equivalent of RecyclerView on Android, which automatically recycles list elements for you:

dart
import'dart:developer'asdeveloper;import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{List<Widget>widgets=[];@overridevoidinitState(){super.initState();for(inti=0;i<100;i++){widgets.add(getRow(i));}}WidgetgetRow(intindex){returnGestureDetector(onTap:(){setState((){widgets.add(getRow(widgets.length));developer.log('Row$index');});},child:Padding(padding:constEdgeInsets.all(10),child:Text('Row$index'),),);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:ListView.builder(itemCount:widgets.length,itemBuilder:(context,index){returngetRow(index);},),);}}

Instead of creating aListView, create aListView.builder that takes two key parameters: the initial length of the list, and an item builder function.

The item builder function is similar to thegetView function in an Android adapter; it takes a position, and returns the row you want rendered at that position.

Finally, but most importantly, notice that theonTap() function doesn't recreate the list anymore, but instead adds to it.

For more information, seeYour first Flutter app codelab.

Working with text

#

How do I set custom fonts on my text widgets?

#

In Xamarin.Forms, you would have to add a custom font in each native project. Then, in yourElement you would assign this font name to theFontFamily attribute usingfilename#fontname and justfontname for iOS.

In Flutter, place the font file in a folder and reference it in thepubspec.yaml file, similar to how you import images.

yaml
fonts:-family:MyCustomFontfonts:-asset:fonts/MyCustomFont.ttf-style:italic

Then assign the font to yourText widget:

dart
@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:constCenter(child:Text('This is a custom font text',style:TextStyle(fontFamily:'MyCustomFont'),),),);}

How do I style my text widgets?

#

Along with fonts, you can customize other styling elements on aText widget. The style parameter of aText widget takes aTextStyle object, where you can customize many parameters, such as:

  • color
  • decoration
  • decorationColor
  • decorationStyle
  • fontFamily
  • fontSize
  • fontStyle
  • fontWeight
  • hashCode
  • height
  • inherit
  • letterSpacing
  • textBaseline
  • wordSpacing

Form input

#

How do I retrieve user input?

#

Xamarin.Formselements allow you to directly query theelement to determine the state of its properties, or whether it's bound to a property in aViewModel.

Retrieving information in Flutter is handled by specialized widgets and is different from how you are used to. If you have aTextFieldor aTextFormField, you can supply aTextEditingController to retrieve user input:

dart
import'package:flutter/material.dart';classMyFormextendsStatefulWidget{constMyForm({super.key});@overrideState<MyForm>createState()=>_MyFormState();}class_MyFormStateextendsState<MyForm>{/// Create a text controller and use it to retrieve the current value/// of the TextField.finalTextEditingControllermyController=TextEditingController();@overridevoiddispose(){// Clean up the controller when disposing of the widget.myController.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Retrieve Text Input')),body:Padding(padding:constEdgeInsets.all(16),child:TextField(controller:myController),),floatingActionButton:FloatingActionButton(// When the user presses the button, show an alert dialog with the// text that the user has typed into our text field.onPressed:(){showDialog(context:context,builder:(context){returnAlertDialog(// Retrieve the text that the user has entered using the// TextEditingController.content:Text(myController.text),);},);},tooltip:'Show me the value!',child:constIcon(Icons.text_fields),),);}}

You can find more information and the full code listing inRetrieve the value of a text field.

What is the equivalent of a Placeholder on an Entry?

#

In Xamarin.Forms, someElements support aPlaceholder property that you can assign a value to. For example:

xml
<Entry Placeholder="This is a hint">

In Flutter, you can easily show a "hint" or a placeholder text for your input by adding anInputDecoration object to thedecoration constructor parameter for the text widget.

dart
TextField(decoration:InputDecoration(hintText:'This is a hint')),

How do I show validation errors?

#

With Xamarin.Forms, if you wished to provide a visual hint of a validation error, you would need to create new properties andVisualElements surrounding theElements that had validation errors.

In Flutter, you pass through an InputDecoration object to the decoration constructor for the text widget.

However, you don't want to start off by showing an error. Instead, when the user has entered invalid data, update the state, and pass a newInputDecoration object.

dart
import'package:flutter/material.dart';voidmain(){runApp(constSampleApp());}classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnconstMaterialApp(title:'Sample App',home:SampleAppPage());}}classSampleAppPageextendsStatefulWidget{constSampleAppPage({super.key});@overrideState<SampleAppPage>createState()=>_SampleAppPageState();}class_SampleAppPageStateextendsState<SampleAppPage>{String?_errorText;String?_getErrorText(){return_errorText;}boolisEmail(Stringem){constStringemailRegexp=r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|'r'(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|'r'(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';finalRegExpregExp=RegExp(emailRegexp);returnregExp.hasMatch(em);}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('Sample App')),body:Center(child:TextField(onSubmitted:(text){setState((){if(!isEmail(text)){_errorText='Error: This is not an email';}else{_errorText=null;}});},decoration:InputDecoration(hintText:'This is a hint',errorText:_getErrorText(),),),),);}}

Flutter plugins

#

Interacting with hardware, third party services, and the platform

#

How do I interact with the platform, and with platform native code?

#

Flutter doesn't run code directly on the underlying platform; rather, the Dart code that makes up a Flutter app is run natively on the device, "sidestepping" the SDK provided by the platform. That means, for example, when you perform a network request in Dart, it runs directly in the Dart context. You don't use the Android or iOS APIs you normally take advantage of when writing native apps. Your Flutter app is still hosted in a native app'sViewController orActivity as a view, but you don't have direct access to this, or the native framework.

This doesn't mean Flutter apps can't interact with those native APIs, or with any native code you have. Flutter providesplatform channels that communicate and exchange data with theViewController orActivity that hosts your Flutter view. Platform channels are essentially an asynchronous messaging mechanism that bridges the Dart code with the hostViewController orActivity and the iOS or Android framework it runs on. You can use platform channels to execute a method on the native side, or to retrieve some data from the device's sensors, for example.

In addition to directly using platform channels, you can use a variety of pre-madeplugins that encapsulate the native and Dart code for a specific goal. For example, you can use a plugin to access the camera roll and the device camera directly from Flutter, without having to write your own integration. Plugins are found onpub.dev, Dart and Flutter's open source package repository. Some packages might support native integrations on iOS, or Android, or both.

If you can't find a plugin on pub.dev that fits your needs, you canwrite your own, andpublish it on pub.dev.

How do I access the GPS sensor?

#

Use thegeolocator community plugin.

How do I access the camera?

#

Thecamera plugin is popular for accessing the camera.

How do I log in with Facebook?

#

To log in with Facebook, use theflutter_facebook_login community plugin.

How do I use Firebase features?

#

Most Firebase functions are covered byfirst party plugins. These plugins are first-party integrations, maintained by the Flutter team:

You can also find some third-party Firebase plugins on pub.dev that cover areas not directly covered by the first-party plugins.

How do I build my own custom native integrations?

#

If there is platform-specific functionality that Flutter or its community plugins are missing, you can build your own following thedeveloping packages and plugins page.

Flutter's plugin architecture, in a nutshell, is much like using an Event bus in Android: you fire off a message and let the receiver process and emit a result back to you. In this case, the receiver is code running on the native side on Android or iOS.

Themes (Styles)

#

How do I theme my app?

#

Flutter comes with a beautiful, built-in implementation of Material Design, which handles much of the styling and theming needs that you would typically do.

Xamarin.Forms does have a globalResourceDictionary where you can share styles across your app. Alternatively, there is Theme support currently in preview.

In Flutter, you declare themes in the top level widget.

To take full advantage of Material Components in your app, you can declare a top level widgetMaterialApp as the entry point to your application.MaterialApp is a convenience widget that wraps a number of widgets that are commonly required for applications implementing Material Design. It builds upon aWidgetsApp by adding Material-specific functionality.

You can also use aWidgetsApp as your app widget, which provides some of the same functionality, but is not as rich asMaterialApp.

To customize the colors and styles of any child components, pass aThemeData object to theMaterialApp widget. For example, in the following code, the color scheme from seed is set to deepPurple and text selection color is red.

dart
classSampleAppextendsStatelessWidget{/// This widget is the root of your application.constSampleApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Sample App',theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),textSelectionTheme:constTextSelectionThemeData(selectionColor:Colors.red,),),home:constSampleAppPage(),);}}

Databases and local storage

#

How do I access shared preferences or UserDefaults?

#

Xamarin.Forms developers will likely be familiar with theXam.Plugins.Settings plugin.

In Flutter, access equivalent functionality using theshared_preferences plugin. This plugin wraps the functionality of bothUserDefaults and the Android equivalent,SharedPreferences.

How do I access SQLite in Flutter?

#

In Xamarin.Forms most applications would use thesqlite-net-pcl plugin to access SQLite databases.

In Flutter, on macOS, Android, and iOS, access this functionality using thesqflite plugin.

Debugging

#

What tools can I use to debug my app in Flutter?

#

Use theDevTools suite for debugging Flutter or Dart apps.

DevTools includes support for profiling, examining the heap, inspecting the widget tree, logging diagnostics, debugging, observing executed lines of code, debugging memory leaks and memory fragmentation. For more information, check out theDevTools documentation.

Notifications

#

How do I set up push notifications?

#

In Android, you use Firebase Cloud Messaging to set up push notifications for your app.

In Flutter, access this functionality using thefirebase_messaging plugin. For more information on using the Firebase Cloud Messaging API, see thefirebase_messaging plugin documentation.

Was this page's content helpful?

Unless stated otherwise, the documentation on this site reflects Flutter 3.38.1. Page last updated on 2025-10-9.View source orreport an issue.


[8]ページ先頭

©2009-2025 Movatter.jp