[ドックで]フラッター。 パート1. Android開発者向け

Flutterはすでに多くの記事を書いています。 毎月人気が高まっています。 したがって、公式のFlutterドキュメントを簡潔なQ&A形式で解釈することにしました。 私のように、多くの人は、まだ機能しないフレームワークのドキュメントを詳細に研究するのに十分な時間がないと思います。



このフレームワークの利点を理解し、それを使用するためにどれだけの努力が必要かを評価したい場合は、catへようこそ。







内容:



  1. 視聴回数



  2. 意図



  3. 非同期UI



  4. プロジェクトの構造とリソース



  5. アクティビティとフラグメント



  6. レイアウト



  7. ジェスチャとタッチイベント処理。



  8. リストビューとアダプター



  9. テキストを操作する



  10. 入力フォーム



  11. Flutterプラグイン



  12. テーマ



  13. データベースとローカルストレージ



  14. 通知





視聴回数



質問:



FlutterのViewと同等のものは何ですか?



答えは:



ウィジェット



違い:



表示-実際には、画面に何が表示されます。 Invalidate()は、変更を表示するために呼び出されます。



ウィジェット-画面に表示される内容の説明。 変更のために新たに作成されます。



追加情報:



Android自体で起動した場合、ViewはWidgetの内部にあります。 FlutterにはMaterial Componentsライブラリが含まれています。 マテリアルデザインガイドラインを実装するウィジェットが含まれています。



質問:



ウィジェットの表示を更新する方法は?



答えは:



StatefulWidgetとその状態を使用します。 Flutterには、 StatelessWidgetStatefulWidgetの 2種類のウィジェットがあります。 それらは同じように機能し、唯一の違いはレンダリング状態にあります。



違い:



StatelessWidgetには不変の状態があります。 テキスト、ロゴなどの表示に適しています。 つまり 画面上の要素が表示時間全体にわたって変化しない場合は、それが適しています。 ステートフルウィジェットのコンテナとしても使用できます。



StatefulWidgetにはState状態があり、現在の状態に関する情報が保存されます。 何らかのアクション(サーバーからの応答、ユーザーがボタンをクリックしたなど)を実行するときに画面上の要素を変更する場合-これはオプションです。



例:



1)StatelessWidget-テキスト



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





2)StatefulWidget-(FloatingActionButton)ボタンをクリックすると、Textウィジェットのテキストが「I Like Flutter」から「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), ), ); } }
      
      





質問:



ウィジェットで画面をレイアウトする方法は? XMLレイアウトファイルはどこにありますか?



答えは:



Flutterには、画面用のXMLレイアウトがありません。 コード内でウィジェットツリーに直接タイプセットされるすべてのもの。



例:



 @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), ), ), ); }
      
      





Flutterのすべてのデフォルトウィジェットは、 ウィジェットカタログで表示できます。



質問:



アプリケーションの実行中にレイアウトでコンポーネントを追加または削除する方法は?



答えは:



状態に応じて目的のウィジェットを返す関数を通じて。



違い:



Androidでは、ViewGroupでaddView()またはremoveView()を実行できます。 Flutterでは、できません ウィジェットは変更されていません。 状態のみが変更できます。



例:



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), ), ); } }
      
      





質問:



ウィジェットをアニメーション化する方法は?



答えは:



Animation <T>抽象クラスの子孫であるAnimationControllerクラスを使用します。 アニメーションの開始に加えて、彼はそれを一時停止、巻き戻し、停止し、反対方向に再生することができます。 画面の再描画を報告するTicker連携します。



違い:



Androidでは、アニメーションをXMLで作成するか、animate()を使用してビューをアニメーション化できます。 Flutterでは、アニメーションはAnimationControllerを使用してコードで記述する必要があります。



追加情報:



詳細については、 アニメーションとモーションウィジェットアニメーションチュートリアル、およびアニメーションの概要をご覧ください



例:



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(); }, ), ); } }
      
      





質問:



Canvasの使用方法



答えは:



AndroidとFlutterのCanvasのAPIは同じです。 同じ低レベルSkiaエンジンを使用します。



違い:



いや



追加情報:



Flutterには、 CustomPaintCustomPainterの 2つのCanvas描画用クラスがあります 。 2番目は、レンダリングアルゴリズムを実装します。



詳細はこちら: StackOverflow



例:



 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; }
      
      





質問:



カスタムウィジェットを作成する方法



答えは:



(継承の代わりに)1つの内部でウィジェットを作成します。



違い:



Androidでは、関心のあるビューから継承し、独自のロジックを追加できます。 Flutterでは、ViewGroupのように見えますが、常にウィジェットのみがStatelessWidgetまたはStatefulWidgetから継承されます。 つまり 新しいウィジェットを作成し、必要なウィジェットのセットをパラメーターまたはフィールドとして使用する必要があります。



例:



 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"), ); }
      
      





意図



質問:



Intent in Flutterの類似物は何ですか?



答えは:



彼はそこにいません。 画面間を移動するには、 NavigatorクラスとRouteクラスを使用します。



外部コンポーネント(カメラやファイルピッカーなど)とやり取りするには、各プラットフォームでプラグインまたはネイティブ統合を使用できます。 ネイティブ統合の詳細: パッケージとプラグインの開発



違い:



FlutterにはActivityやFragmentなどはありません。 ナビゲーター(ナビゲーター)とルート(ルート)があります。 Flutterのアプリケーションは、さまざまな画面がさまざまなフラグメントを表すシングルアクティビティアプリケーションに似ており、FragmentManagerがそれらを制御します。 Navigatorは、原則としてFragmentManagerに似ています。 指定したルートにプッシュ()またはポップ()できます。 ルートは一種のフラグメントですが、Flutterではスクリーンまたはページと比較するのが一般的です。



Androidでは、AndroidManifest.xmlでナビゲートできるすべてのアクティビティを記述します。



Flutterには2つの方法があります。





例:



 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');
      
      





質問:



他のアプリケーションからのインテントを処理する方法は?



答えは:



MethodChannelを介してAndroidアプリケーション層と対話する。



例:



AndroidManifest.xmlにintent-filterを記述します。



 <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>
      
      





MainActivityでインテントを処理し、MethodChannelを介してFlutterからコードを呼び出します。



 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); } }
      
      





ウィジェットの描画が開始されると、データをリクエストします。



 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; }); } } }
      
      





質問:



startActivityForResult()の類似物は何ですか?



答えは:



awaitキーワードとFutureクラスの結果。



違い:



AndroidでstartActivityForResult()を呼び出した後、onActivityResult()で処理を実装する必要があります。 Flutterは何も実装する必要はありません。 navigatorメソッドpush()はFutureオブジェクトを返します。



例:



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





そして、「/ location」画面で座標を取得したら、pop()を実行します。



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





非同期UI



質問:



FlutterのrunOnUiThread()の類似物は何ですか?



答えは:



DartはIsolatesで実行されるシングルスレッド実行モデルを実装しています。 非同期実行の場合は、async / awaitを使用します。これは、C#、JavaScript、またはKotlinコルーチンでおなじみかもしれません。



例:



リクエストを実行し、UIを更新するための結果を返します。



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





リクエストへの応答を受信したら、 setState()メソッドを呼び出して、新しいデータでウィジェットツリーを再描画する必要があります。



例:



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); }); } }
      
      





質問:



バックグラウンドスレッドでコードを実行する方法



答えは:



上記のように-async / awaitと分離(分離)を使用します。



違い:



Androidでは、すぐにAsyncTaskを使用できます。 onPreExecute()doInBackground()onPostExecute()を実装する必要があります。 Flutterでは、箱から出してすぐにasync / awaitを使用するだけで、残りはDartが処理します。



例:



ここでは、dataLoader()メソッドが分離されています。 単独で、大きなJSONの解析、暗号化、画像処理などの重い操作を実行できます。



 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; } }
      
      





質問:



OkHttpのFlutterと同等のものは何ですか?



答えは:



Flutterには独自のHTTPパッケージがあります



追加情報:



これまでのところ、すべてのOkHttp機能がHTTPパッケージに実装されているわけではないため、欠落している機能の多くは抽象化されており、必要に応じて自分で実装できます。



例:



HTTPパッケージを使用するには、pubspec.yamlに依存関係として追加します。



 dependencies: ... http: ^0.11.3+16
      
      





要求を実行するには、非同期関数http.get()でawaitを呼び出します。



 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); }); } }
      
      





質問:



進捗状況を表示する方法は?



答えは:



ProgressIndicatorウィジェットを使用します。



例:



 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); }); } }
      
      





プロジェクトの構造とリソース



質問:



異なる解像度のリソースをどこに保存しますか?



答えは:



資産内。



違い:



Androidでは、リソースにはresフォルダーがあり、アセットがあります。 Flutterにはアセットのみがあります。 アセットフォルダーはプロジェクト内の任意の場所に配置できます。最も重要なのは、pubspec.yamlファイルにそのフォルダーへのパスを書き込むことです。



追加情報:



AndroidとFlutterのグラフィックリソースのサイズの比較。

Android密度修飾子 フラッターピクセル比
ldpi 0.75x
mdpi 1.0倍
hdpi 1.5倍
xhdpi 2.0倍
xxhdpi 3.0倍
xxxhdpi 4.0倍
FlutterはAssetManagerまたはAssetで始まる特殊なクラスを使用して、コード内のリソースを使用します。



例:



AssetManager:



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





リソースの場所:



 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
      
      





pubspec.yamlファイルのパス:



 assets: - images/my_icon.jpeg
      
      





AssetImageの使用:



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





アセットを直接使用する:



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





質問:



文字列をどこに保存しますか? それらをローカライズする方法は?



答えは:



静的フィールドに保存します。 intlパッケージを使用してローカライズします



例:



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





質問:



gradleファイルの類似物は何ですか? 依存関係を追加する方法は?



答えは:



pubspec.yaml。



追加情報:



Flutterは、ビルドをネイティブのAndroidおよびiOSビルダーに委任します。 Pubの Flutterで人気のあるすべてのライブラリのリストを参照してください。



アクティビティとフラグメント



質問:



Flutterのアクティビティフラグメントに相当するものは何ですか?



答えは:



Flutterのすべてはウィジェットです。 UIを操作するためのアクティビティとフラグメントの役割は、ウィジェットが果たします。 ナビゲーションの段落で述べたように、ナビゲーションの役割はナビゲータとルートです。



追加情報:



Flutter for Android Developers:FlutterでアクティビティUIを設計する方法



質問:



ライフサイクルイベントの処理方法



答えは:



WidgetsBindingおよびdidChangeAppLifecycleState()メソッドを使用します。



追加情報:



FlutterはネイティブコードでFlutterActivityを使用し、Flutterエンジンは処理状態の変更を可能な限り目立たなくします。 ただし、状態に応じていくつかの作業を行う必要がある場合、ライフサイクルはわずかに異なります。





これについては、 AppLifecycleStatusのドキュメントで詳しく説明しています



例:



 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())); }
      
      





レイアウト



質問:



LinearLayoutの類似物はですか?



答えは:



水平方向の 、垂直方向の



追加情報:



Android開発者向けのFlutter:FlutterでLinearLayoutを設計する方法



例:



 @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'), ], ); }
      
      





質問:



RelativeLayoutと同等のものは何ですか?



答えは:



ウィジェットスタック



詳細:

Stackoverflow



質問:



ScrollViewの類似物はですか?



答えは:



ウィジェット付きのリストビュー



例:



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





質問:



ポートレートとランドスケープ間の移行を処理する方法は?



答えは:



AndroidManifest.xmlに含まれている場合、FlutterViewはフリップを処理します

android:configChanges = "orientation | screenSize"



ジェスチャとタッチイベント処理



質問:



FlutterのウィジェットにonClickリスナーを追加するには?



答えは:



ウィジェットがクリックをサポートしている場合、onPressed()。 そうでない場合は、onTap()で。



例:



onPressed()で:



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





onTap()で:



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





質問:



ウィジェットで他のジェスチャーを処理する方法は?



答えは:



GestureDetectorを使用します。 次のアクションを処理できます。



タップ





ダブルタップ





長押し





垂直ドラッグ





水平ドラッグ





例:



DoubleTapでの処理:



 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(); } }, ), )); } }
      
      





リストビューとアダプター



質問:



FlutterのListViewの類似物は何ですか?



答えは:



ListView



違い:



Flutterは、アイテムのクリーンアップと再利用について考える必要はありません(これは、ViewHolderパターンを使用して、AndroidでListView / RecyclerViewが行うことです)。



例:



 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; } }
      
      





質問:



どの要素がクリックされたかを調べる方法は?



答えは:



GestureDetectorでアイテムをラップします。



例:



 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; } }
      
      





質問:



ListViewを動的に更新する方法は?



答えは:



小さいデータセットがある場合、これはsetState()を使用し実行できます。 データセットが大きい場合は、 RecyclerViewに相当するListView.Builderを使用します。



例:



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'); }); }, ); } }
      
      





テキストを操作する



質問:



カスタムフォントの使用方法



答えは:



フォルダーにフォントファイルを置き(名前を自分で考えて)、pubspec.yamlでそのファイルへのパスを指定するだけです。



例:



 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'), ), ), ); }
      
      





質問:



テキストウィジェットのスタイル設定方法



答えは:



パラメーターの使用:





入力フォーム



詳細はこちら: テキストフィールドの値を取得します



質問:



TextInputのヒントの類似物は何ですか?



答えは:



ツールチップInputDecorationを使用して表示でき、コンストラクターとしてウィジェットに渡します。



例:



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





質問:



検証エラーを表示する方法は?



答えは:



InputDecorationとその状態についても同様です。



例:



 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



質問:



GPS?



答えは:



geolocator .



質問:



?



答えは:



image_picker .



質問:



Facebook?



答えは:



flutter_facebook_login .



質問:



Firebase?



答えは:



Firebase Flutter first party plugins .





質問:



() ?



答えは:



Flutter EventBus . : developing packages and plugins .



質問:



NDK?



答えは:



NDK- Flutter. Flutter .



Themes



質問:



(Theme) ?



答えは:



MaterialApp WidgetApp .



例:



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







質問:



Shared Preferences?



答えは:



Shared_Preferences plugin ( NSUserDefaults iOS ).



例:



 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); }
      
      





質問:



SQLite Flutter?



答えは:



SQFlite .





質問:



push-?



答えは:



Firebase_Messaging .



おわりに



. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .

2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . . Google Play!



All Articles