📜 ⬆️ ⬇️

[On the docks] Flutter. Part 1. For Android developers

Many articles have been written about Flutter. Every month it becomes more popular. Therefore, I decided to interpret the official Flutter documentation in a concise question-answer format. I think many, like me, do not have enough free time for a detailed study of the framework documentation, with which they are not working yet.

If you want to understand how good this framework is and how much effort you will have to make to use it - welcome under cat.



Content:


  1. Views

  2. Intents

  3. Async ui

  4. Project structure and resources

  5. Activities & Fragments

  6. Layouts

  7. Gestures and touch event handling.

  8. ListViews & Adapters

  9. Work with text

  10. Entry form

  11. Flutter Plugins

  12. Themes

  13. Databases and local storage

  14. Notifications


Views


Question:


What is the equivalent of View in Flutter?
')

Answer:


Widget

Differences:


View is actually what will be on the screen. Invalidate () is called to display changes.

Widget - a description of what will be on the screen. To change is created again.

Additional Information:


When running on the Android itself, under the hood Widget is a View. Flutter includes the Material Components library. It contains widgets that implement material design guidelines .

Question:


How to update the display of widgets?

Answer:


Using StatefulWidget and its State . Flutter has 2 kinds of widgets: StatelessWidget and StatefulWidget . They work the same way, the only difference is in the rendering state.

Differences:


StatelessWidget has an unchanged state. Suitable for displaying text, logo, etc. Those. If the element on the screen should not change during the entire display, it means that it suits you. It can also be used as a container for stateful widgets.

StatefulWidget has a State state that stores current state information. If you want to change the item on the screen when performing some action (the answer came from the server, the user pressed the button, etc.) - this is your option.

Example:


1) StatelessWidget - Text

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

2) StatefulWidget - when you click on the button (FloatingActionButton), the text in the Text widget changes from “I Like Flutter” to “Flutter is Awesome!”.

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { //     . @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { //   String textToShow = "  Flutter"; void _updateText() { setState(() { //   textToShow = "Flutter !"; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center(child: Text(textToShow)), floatingActionButton: FloatingActionButton( onPressed: _updateText, tooltip: ' ', child: Icon(Icons.update), ), ); } } 

Question:


How to typeset the screen with widgets? Where is the xml layout file?

Answer:


Flutter does not have XML layout. Everything is made up in the widget tree right in the code.

Example:


 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: MaterialButton( onPressed: () {}, child: Text('Hello'), padding: EdgeInsets.only(left: 10.0, right: 10.0), ), ), ); } 

All default widgets in Flutter can be viewed in the widget catalog .

Question:


How to add or remove a component in the layout while the application is running?

Answer:


Through a function that will return the desired widget depending on the state.

Differences:


In Android, you can addView () or removeView () in the ViewGroup. In Flutter, this is impossible, because widgets are unchanged. Only their condition can change.

Example:


How to change Text to Button by clicking on the FloatingActionButton.

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { //     . @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { //     bool toggle = true; void _toggle() { setState(() { toggle = !toggle; }); } _getToggleChild() { if (toggle) { return Text('Toggle One'); } else { return MaterialButton(onPressed: () {}, child: Text('Toggle Two')); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: _getToggleChild(), ), floatingActionButton: FloatingActionButton( onPressed: _toggle, tooltip: 'Update Text', child: Icon(Icons.update), ), ); } } 

Question:


How to animate widgets?

Answer:


Using the AnimationController class, which is a descendant of the abstract Animation <T> class. In addition to starting the animation, he can pause it, rewind, stop and play in the opposite direction. It works with the help of Ticker , which reports the screen redrawing.

Differences:


In Android, you can create animations in XML or animate View using animate (). In Flutter, the animation needs to be written in code using the AnimationController.

Additional Information:


You can learn more in the Animation & Motion widgets , Animations tutorial and Animations overview .

Example:


Fade-animation logo Flutter.

 import 'package:flutter/material.dart'; void main() { runApp(FadeAppTest()); } class FadeAppTest extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Fade Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyFadeTest(title: 'Fade Demo'), ); } } class MyFadeTest extends StatefulWidget { MyFadeTest({Key key, this.title}) : super(key: key); final String title; @override _MyFadeTest createState() => _MyFadeTest(); } class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin { AnimationController controller; CurvedAnimation curve; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Container( child: FadeTransition( opacity: curve, child: FlutterLogo( size: 100.0, )))), floatingActionButton: FloatingActionButton( tooltip: 'Fade', child: Icon(Icons.brush), onPressed: () { controller.forward(); }, ), ); } } 

Question:


How to use Canvas ?

Answer:


Android and Flutter have the same API for Canvas, since they use the same low-level Skia engine.

Differences:


Not.

Additional Information:


Flutter has two drawing classes on Canvas — CustomPaint and CustomPainter . The second implements your rendering algorithm.

Read more here: StackOverflow

Example:


 import 'package:flutter/material.dart'; void main() => runApp(MaterialApp(home: DemoApp())); class DemoApp extends StatelessWidget { Widget build(BuildContext context) => Scaffold(body: Signature()); } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } } class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0; for (int i = 0; i < points.length - 1; i++) { if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], paint); } } bool shouldRepaint(SignaturePainter other) => other.points != points; } 

Question:


How to create custom widgets?

Answer:


Link widgets inside one (instead of inheritance).

Differences:


In Android, we can inherit from the View we are interested in and add our logic. In Flutter, this looks like a ViewGroup, only a widget is always inherited from a StatelessWidget or a StatefulWidget. Those. You need to create a new widget and use in it the set of widgets you need as parameters or fields.

Example:


 class CustomButton extends StatelessWidget { final String label; CustomButton(this.label); @override Widget build(BuildContext context) { return RaisedButton(onPressed: () {}, child: Text(label)); } } @override Widget build(BuildContext context) { return Center( child: CustomButton("Hello"), ); } 

Intents


Question:


What is the analogue content in Flutter?

Answer:


He is not. Navigator and Route classes are used to navigate between screens.

To interact with external components (for example, a camera or a file picker), you can use plug-ins or native integration on each platform. Learn more about native integration: Developing Packages and Plugins .

Differences:


Flutter has no such concepts as Activity and Fragment. There is a Navigator (navigator) and Routes (routes). The application on Flutter resembles a single-activity application, where different screens are different fragments, and FragmentManager controls them. Navigator is similar to FragmentManager in the way it works. It can push () or pop () the route you specify. Route is a kind of Fragment, but in Flutter it is customary to compare it with a screen or page.

In Android, we describe all the Activities between which we can navigate in AndroidManifest.xml.

Flutter has two options:


Example:


 void main() { runApp(MaterialApp( home: MyAppHome(), // becomes the route named '/' routes: <String, WidgetBuilder> { '/a': (BuildContext context) => MyPage(title: 'page A'), '/b': (BuildContext context) => MyPage(title: 'page B'), '/c': (BuildContext context) => MyPage(title: 'page C'), }, )); } Navigator.of(context).pushNamed('/b'); 

Question:


How to handle incoming intents from other applications?

Answer:


Interacting with the Android application layer via MethodChannel .

Example:


We register intent-filter in AndroidManifest.xml:

 <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <!-- ... --> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity> 

We process the Intent in the MainActivity and from Flutter we call the code through MethodChannel:

 package com.example.shared; import android.content.Intent; import android.os.Bundle; import java.nio.ByteBuffer; import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.ActivityLifecycleListener; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { private String sharedText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { handleSendText(intent); // Handle text being sent } } new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { if (call.method.contentEquals("getSharedText")) { result.success(sharedText); sharedText = null; } } }); } void handleSendText(Intent intent) { sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); } } 

We request data when the widget starts to draw:

 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample Shared App Handler', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { static const platform = const MethodChannel('app.channel.shared.data'); String dataShared = "No data"; @override void initState() { super.initState(); getSharedText(); } @override Widget build(BuildContext context) { return Scaffold(body: Center(child: Text(dataShared))); } getSharedText() async { var sharedData = await platform.invokeMethod("getSharedText"); if (sharedData != null) { setState(() { dataShared = sharedData; }); } } } 

Question:


What is the equivalent of startActivityForResult () ?

Answer:


The await keyword and the result of the Future class .

Differences:


After calling startActivityForResult () in Android, we need to implement the processing in onActivityResult (). Flutter doesn't need to implement anything, since the push () navigator method returns a Future object.

Example:


 Map coordinates = await Navigator.of(context).pushNamed('/location'); 

And when on the screen '/ location' got the coordinates, do pop ():

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

Async ui


Question:


What is the equivalent of runOnUiThread () in Flutter?

Answer:


In Dart, a single-flow execution model is implemented that works on isolations ( Isolates ). Asynchronous execution uses async / await, which you may be familiar with from C #, JavaScript, or Kotlin coroutines.

Example:


Execute the query and return the result for updating the UI:

 loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } 

When the answer to the request is received, you need to call the setState () method to redraw the widget tree with new data.

Example:


Download and update data in ListView :

 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); })); } Widget getRow(int i) { return Padding( padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}") ); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Question:


How to execute code in a background thread?

Answer:


As mentioned above - using async / await and isolations (Isolate).

Differences:


Out of the box in Android you can use AsyncTask. It needs to implement onPreExecute () , doInBackground () , onPostExecute () . In Flutter out of the box, you just need to use async / await, Dart will take care of the rest.

Example:


Here the dataLoader () method is isolated. In isolation, you can run heavy operations, such as parsing large JSON, encryption, image processing, etc.

 loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // The entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; }   : import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:async'; import 'dart:isolate'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { if (widgets.length == 0) { return true; } return false; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // the entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; } } 

Question:


What is the equivalent of OkHttp in Flutter?

Answer:


Flutter has its own HTTP package .

Additional Information:


So far, not all features from OkHttp are implemented in the HTTP Package, so many of the missing ones are included in the abstraction and you can implement them yourself as needed.

Example:


To use the HTTP package, add it as a dependency in pubspec.yaml:

 dependencies: ... http: ^0.11.3+16 

To execute the request, call await in the async function http.get ():

 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; [...] loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Question:


How to show progress?

Answer:


Using the ProgressIndicator widget.

Example:


 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { return widgets.length == 0; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Project structure and resources


Question:


Where to store resources of different resolutions?

Answer:


In assets.

Differences:


In Android, resources have a res folder and there are assets. Flutter has only assets. The assets folder can be located anywhere in the project, the main thing is to set the path to it in the pubspec.yaml file.

Additional Information:


Matching the size of graphics resources in Android and Flutter.
Android density qualifierFlutter pixel ratio
ldpi0.75x
mdpi1.0x
hdpi1.5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x
Flutter uses AssetManager or specialized classes starting with Asset to use resources in the code.

Example:


AssetManager:

 val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png") 

Resource Locations:

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

Path in pubspec.yaml file:

 assets: - images/my_icon.jpeg 

Using AssetImage :

 return AssetImage("images/a_dot_burr.jpeg"); 

Using asset directly:

 @override Widget build(BuildContext context) { return Image.asset("images/my_image.png"); } 

Question:


Where to store the lines? How to localize them?

Answer:


Store in static fields. Localize with intl package .

Example:


 class Strings { static String welcomeMessage = "Welcome To Flutter"; } Text(Strings.welcomeMessage) 

Question:


What is an analogue gradle file? How to add dependencies?

Answer:


pubspec.yaml.

Additional Information:


Flutter delegates the build to native Android and iOS builders. View a list of all popular libraries for Flutter in the Pub .

Activities & Fragments


Question:


What is the equivalent of Activity and Fragment in Flutter?

Answer:


In Flutter, everything is widgets. The role of activations and fragments for working with UI is performed by widgets. And the role of navigation, as mentioned in the paragraph about navigation, is Navigator and Route.

Additional Information:


Flutter For Android Developers: UF in Flutter .

Question:


How to handle life cycle events?

Answer:


Using the WidgetsBinding and didChangeAppLifecycleState () method.

Additional Information:


Flutter uses FlutterActivity in the native code, and the Flutter engine makes the processing of state changes as inconspicuous as possible. But if you still need to do any work depending on the state, then the life cycle is slightly different:


This is described in more detail in the AppLifecycleStatus documentation .

Example:


 import 'package:flutter/widgets.dart'; class LifecycleWatcher extends StatefulWidget { @override _LifecycleWatcherState createState() => _LifecycleWatcherState(); } class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver { AppLifecycleState _lastLifecycleState; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { setState(() { _lastLifecycleState = state; }); } @override Widget build(BuildContext context) { if (_lastLifecycleState == null) return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr); return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.', textDirection: TextDirection.ltr); } } void main() { runApp(Center(child: LifecycleWatcher())); } 

Layouts


Question:


What is the equivalent of LinearLayout ?

Answer:


Row - for horizontal layout, Column - for vertical.

Additional Information:


Flutter For Android Developers: How To Design LinearLayout in Flutter?

Example:


 @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Column One'), Text('Column Two'), Text('Column Three'), Text('Column Four'), ], ); } 

Question:


What is the equivalent of RelativeLayout ?

Answer:


Stack widget.

More details:

Stackoverflow

Question:


What is the analogue of ScrollView ?

Answer:


ListView with widgets.

Example:


 @override Widget build(BuildContext context) { return ListView( children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); } 

Question:


How to handle transitions between portrait and landscape?

Answer:


FlutterView handles coups if AndroidManifest.xml contains
android: configChanges = "orientation | screenSize"

Gestures and touch event handling


Question:


How to add an onClick listener for a widget in Flutter?

Answer:


If the widget supports clicks, then in onPressed (). If not, then onTap ().

Example:


In onPressed ():

 @override Widget build(BuildContext context) { return RaisedButton( onPressed: () { print("click"); }, child: Text("Button")); } 

In onTap ():

 class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: FlutterLogo( size: 200.0, ), onTap: () { print("tap"); }, ), )); } } 

Question:


How to handle other gestures on widgets?

Answer:


Using GestureDetector . They can handle the following actions:

Tap



Double tap



Long press



Vertical drag



Horizontal drag



Example:


Processing onDoubleTap:

 AnimationController controller; CurvedAnimation curve; @override void initState() { controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: RotationTransition( turns: curve, child: FlutterLogo( size: 200.0, )), onDoubleTap: () { if (controller.isCompleted) { controller.reverse(); } else { controller.forward(); } }, ), )); } } 

ListViews & Adapters


Question:


What is the equivalent of a ListView in Flutter?

Answer:


ListView .

Differences:


In Flutter, you don’t need to think about cleaning up and reusing items (what ListView / RecyclerView does in Android, using the ViewHolder pattern).

Example:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i"))); } return widgets; } } 

Question:


How do I know which item was pressed?

Answer:


Wrapping an item in a GestureDetector .

Example:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { print('row tapped'); }, )); } return widgets; } } 

Question:


ListView ?

Answer:


, setState() . , ListView.Builder , RecyclerView .

Example:


setState() :

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = <Widget>[]; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: widgets), ); } Widget getRow(int i) { return GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { setState(() { widgets = List.from(widgets); widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } } 

ListView.Builder :

 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = <Widget>[]; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); })); } Widget getRow(int i) { return GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { setState(() { widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } } 


Question:


?

Answer:


( ) pubspec.yaml.

Example:


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

 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: Text( 'This is a custom font text', style: TextStyle(fontFamily: 'MyCustomFont'), ), ), ); } 

Question:


?

Answer:


:



: Retrieve the value of a text field .

Question:


hint TextInput ?

Answer:


InputDecoration , .

Example:


 body: Center( child: TextField( decoration: InputDecoration(hintText: "This is a hint"), ) ) 

Question:


?

Answer:


— InputDecoration .

Example:


 import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { String _errorText; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: TextField( onSubmitted: (String text) { setState(() { if (!isEmail(text)) { _errorText = 'Error: This is not an email'; } else { _errorText = null; } }); }, decoration: InputDecoration(hintText: "This is a hint", errorText: _getErrorText()), ), ), ); } _getErrorText() { return _errorText; } bool isEmail(String em) { String emailRegexp = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; RegExp regExp = RegExp(emailRegexp); return regExp.hasMatch(em); } } 

Flutter


Question:


GPS?

Answer:


geolocator .

Question:


?

Answer:


image_picker .

Question:


Facebook?

Answer:


flutter_facebook_login .

Question:


Firebase?

Answer:


Firebase Flutter first party plugins .


Question:


() ?

Answer:


Flutter EventBus . : developing packages and plugins .

Question:


NDK?

Answer:


NDK- Flutter. Flutter .

Themes


Question:


(Theme) ?

Answer:


MaterialApp WidgetApp .

Example:


 class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, textSelectionColor: Colors.red ), home: SampleAppPage(), ); } } 


Question:


Shared Preferences?

Answer:


Shared_Preferences plugin ( NSUserDefaults iOS ).

Example:


 import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { runApp( MaterialApp( home: Scaffold( body: Center( child: RaisedButton( onPressed: _incrementCounter, child: Text('Increment Counter'), ), ), ), ), ); } _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); prefs.setInt('counter', counter); } 

Question:


SQLite Flutter?

Answer:


SQFlite .

Notifications


Question:


push-?

Answer:


Firebase_Messaging .

Conclusion


. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . . Google Play!

Source: https://habr.com/ru/post/442432/


All Articles