Xamarin.Forms 開発者向けの Flutter
このドキュメントは Xamarin.Forms 開発者を対象としています。 既存の知識を応用したいと考えている Flutter を使用してモバイル アプリを構築します。 Xamarin.Forms フレームワークの基本を理解していれば、 このドキュメントを Flutter 開発のスタート地点として使用できます。
Android と iOS の知識とスキルセット Flutter で構築する場合に重要です。 Flutter はネイティブ オペレーティング システム構成に依存しているため、 ネイティブ Xamarin.Forms プロジェクトを構成する方法と同様です。 Flutter Frameworks は、単一の UI を作成する方法にも似ています。 複数のプラットフォームで使用されています。
このドキュメントは、飛び回ってクックブックとして使用できます。 自分のニーズに最も関連する質問を見つけます。
プロジェクトのセットアップ
アプリはどのように起動しますか?
Xamarin.Forms のプラットフォームごとに、
あなたはそれを呼びますLoadApplication
方法、
これにより、新しいアプリケーションが作成され、アプリが起動されます。
LoadApplication(new App());
Flutter では、デフォルトのメイン エントリ ポイントは次のとおりです。main
Flutter アプリをロードする場所。
void main() {
runApp(const MyApp());
}
Xamarin.Forms では、Page
にMainPage
のプロパティApplication
クラス。
public class App : Application
{
public App()
{
MainPage = new ContentPage
{
Content = new Label
{
Text = "Hello World",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
}
};
}
}
Flutter では、アプリケーション自体も含めて「すべてがウィジェット」です。
次の例は、MyApp
、簡単なアプリケーションWidget
。
class MyApp extends StatelessWidget {
/// This widget is the root of your application.
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: Text(
'Hello World!',
textDirection: TextDirection.ltr,
),
);
}
}
ページはどのように作成しますか?
Xamarin.Forms には多くの種類のページがあります。ContentPage
が最も一般的です。
Flutter では、ルート ページを保持するアプリケーション ウィジェットを指定します。
を使用できますMaterialApp
をサポートするウィジェットマテリアルデザイン、
または、CupertinoApp
iOS スタイルのアプリをサポートするウィジェット、
または、より低いレベルを使用することもできますWidgetsApp
、
好きなようにカスタマイズできます。
次のコードは、ステートフル ウィジェットであるホーム ページを定義します。 Flutter では、すべてのウィジェットは不変です。 ただし、次の 2 種類のウィジェットがサポートされています。ステートフルとステートレス。 ステートレス ウィジェットの例としては、タイトル、アイコン、画像などがあります。
次の例では、MaterialApp
、
ルートページをhome
財産。
class MyApp extends StatelessWidget {
/// This widget is the root of your application.
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
ここから、実際の最初のページは別のページになりますWidget
、
そこで自分の状態を作成します。
あステートフルウィジェットなどMyHomePage
以下の 2 つの部分で構成されます。
最初の部分はそれ自体不変であり、State
物体
オブジェクトの状態を保持します。のState
オブジェクトは永続します
ウィジェットの寿命。
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
のState
オブジェクトはbuild()
ステートフル ウィジェットのメソッド。
ウィジェット ツリーの状態が変化したら、次の呼び出しを行います。setState()
、
これにより、UI のその部分のビルドがトリガーされます。
必ず電話してくださいsetState()
必要な場合にのみ、
変更されたのはウィジェット ツリーの部分のみです。
または、UI のパフォーマンスが低下する可能性があります。
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
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>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
Flutter では、UI (ウィジェット ツリーとも呼ばれます) は不変です。
つまり、一度構築すると状態を変更することはできません。
フィールドを変更すると、State
クラスを作ってから電話するsetState()
ウィジェット ツリー全体を再度再構築します。
この UI の生成方法は Xamarin.Forms とは異なります。 しかし、このアプローチには多くの利点があります。
ビュー
Flutter のページまたは要素に相当するものは何ですか?
ContentPage
、TabbedPage
、FlyoutPage
あらゆるタイプのページです
Xamarin.Forms アプリケーションで使用する可能性があります。
これらのページは保持されますElement
s さまざまなコントロールを表示します。
Xamarin.Forms では、Entry
またButton
の例ですElement
。
Flutter では、ほとんどすべてがウィジェットです。
あPage
と呼ばれるRoute
Flutter では、ウィジェットです。
ボタン、プログレスバー、アニメーションコントローラーはすべてウィジェットです。
ルートを構築するときは、ウィジェット ツリーを作成します。
flutterには以下が含まれます材料成分図書館。 これらは、マテリアル デザインのガイドライン。 マテリアル デザインは柔軟なデザイン システムですすべてのプラットフォーム向けに最適化、iOSを含む。
しかし、Flutter は柔軟で表現力が十分にあります あらゆるデザイン言語を実装します。 たとえば、iOS では、クパチーノのウィジェット次のようなインターフェイスを生成しますAppleのiOSデザイン言語。
ウィジェットを更新するにはどうすればよいですか?
Xamarin.Forms では、それぞれPage
またElement
ステートフルなクラスであり、
プロパティとメソッドがあります。
更新しますElement
プロパティを更新することで、
そしてこれはネイティブ コントロールに伝播されます。
flutterでは、Widget
は不変であり、直接更新することはできません
プロパティを変更する場合は、代わりにウィジェットの状態を操作する必要があります。
ここから、ステートフル ウィジェットとステートレス ウィジェットの概念が生まれます。
あStatelessWidget
それはまさにそのように聞こえます—
状態情報を持たないウィジェット。
StatelessWidgets
ユーザーインターフェイスの一部である場合に便利です
あなたが説明しているのは何にも依存していません
オブジェクト内の構成情報以外。
たとえば、Xamarin.Forms では、これは同様です
を配置するImage
あなたのロゴと一緒に。
実行中にロゴが変わることはありませんが、
だから、を使用してくださいStatelessWidget
flutterで。
受信したデータに基づいて動的にUIを変更したい場合
HTTP 呼び出しまたはユーザー操作を行った後、
それならあなたは協力しなければなりませんStatefulWidget
そして、Flutter フレームワークに次のように伝えます。
ウィジェットのState
更新されました、
そのウィジェットを更新できるようになります。
ここで注意すべき重要なことは核心です
ステートレス ウィジェットとステートフル ウィジェットはどちらも同じように動作します。
すべてのフレームを再構築しますが、違いは次のとおりです。
のStatefulWidget
がありますState
物体
フレーム全体で状態データを保存し、それを復元します。
迷った場合は、次のルールを常に覚えておいてください: ウィジェットが変更された場合 (ユーザーの操作などのため) ステートフルです。 ただし、ウィジェットが変更に反応する場合、それを含む親ウィジェットは、 それ自体が変化に反応しない場合は、ステートレスのままです。
次の例は、StatelessWidget
。
共通のStatelessWidget
それはText
ウィジェット。
の実装を見てみると、Text
ウィジェット
サブクラスが見つかりますStatelessWidget
。
const Text(
'I like Flutter!',
style: TextStyle(fontWeight: FontWeight.bold),
);
ご覧のとおり、Text
ウィジェットには状態情報が関連付けられていません。
コンストラクターで渡されたものだけをレンダリングします。
しかし、「I Like Flutter」を動的に変化させたい場合はどうすればよいでしょうか。
たとえば、FloatingActionButton
?
これを実現するには、Text
のウィジェットStatefulWidget
ユーザーがボタンをクリックすると更新されます。
次の例に示すように:
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
/// Default placeholder text
String textToShow = 'I Like Flutter';
void _updateText() {
setState(() {
// Update the text
textToShow = 'Flutter is Awesome!';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: Center(child: Text(textToShow)),
floatingActionButton: FloatingActionButton(
onPressed: _updateText,
tooltip: 'Update Text',
child: const Icon(Icons.update),
),
);
}
}
ウィジェットをレイアウトするにはどうすればよいですか? XAML ファイルに相当するものは何ですか?
Xamarin.Forms では、ほとんどの開発者が XAML でレイアウトを作成します。 ただし、C# の場合もあります。 Flutter では、コード内でウィジェット ツリーを使用してレイアウトを作成します。
次の例は、パディング付きの単純なウィジェットを表示する方法を示しています。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.only(left: 20, right: 30),
),
onPressed: () {},
child: const Text('Hello'),
),
),
);
}
Flutter が提供するレイアウトは、ウィジェットカタログ。
レイアウトに要素を追加または削除するにはどうすればよいですか?
Xamarin.Forms では、Element
コードで。
これには、Content
財産または呼び出しAdd()
またRemove()
それがリストだったら。
Flutter では、ウィジェットは不変であるため、直接同等のものはありません。 代わりに、ウィジェットを返す関数を親に渡すことができます。 そしてその子の作成をブールフラグで制御します。
次の例は、2 つのウィジェットを切り替える方法を示しています。
ユーザーがクリックすると、FloatingActionButton
:
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
/// Default value for toggle
bool toggle = true;
void _toggle() {
setState(() {
toggle = !toggle;
});
}
Widget _getToggleChild() {
if (toggle) {
return const Text('Toggle One');
}
return CupertinoButton(
onPressed: () {},
child: const Text('Toggle Two'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: Center(child: _getToggleChild()),
floatingActionButton: FloatingActionButton(
onPressed: _toggle,
tooltip: 'Update Text',
child: const Icon(Icons.update),
),
);
}
}
ウィジェットをアニメーション化するにはどうすればよいですか?
Xamarin.Forms では、ViewExtensions を使用して単純なアニメーションを作成します。
などの方法が含まれますFadeTo
とTranslateTo
。
これらのメソッドをビューで使用します
必要なアニメーションを実行します。
<Image Source="{Binding MyImage}" x:Name="myImage" />
次に、コードビハインドまたは動作で、これは画像をフェードインします。 1 秒間にわたって。
myImage.FadeTo(0, 1000);
Flutter では、アニメーション ライブラリを使用してウィジェットをアニメーション化します。
ウィジェットをアニメーション化されたウィジェット内にラップすることによって。
を使用してくださいAnimationController
、これはAnimation<double>
アニメーションを一時停止、シーク、停止、反転できます。
それには、Ticker
これは、vsync が発生したときに通知します。
0 と 1 の間の線形補間を生成します。
実行中の各フレームで。
次に、1 つ以上を作成しますAnimation
s をコントローラーに取り付けます。
たとえば、次のように使用できます。CurvedAnimation
補間された曲線に沿ってアニメーションを実装します。
この意味で、コントローラーはアニメーションの進行の「マスター」ソースです。
そしてそのCurvedAnimation
曲線を計算します
これは、コントローラーのデフォルトの直線運動を置き換えます。
ウィジェットと同様に、Flutter のアニメーションは合成で動作します。
ウィジェット ツリーを構築するときに、Animation
ウィジェットのアニメーション化されたプロパティに、
の不透明度などFadeTransition
、
そしてコントローラーにアニメーションを開始するように指示します。
次の例は、FadeTransition
それは色褪せる
を押すとウィジェットがロゴに変わりますFloatingActionButton
:
import 'package:flutter/material.dart';
void main() {
runApp(const FadeAppTest());
}
class FadeAppTest extends StatelessWidget {
/// This widget is the root of your application.
const FadeAppTest({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Fade Demo',
home: MyFadeTest(title: 'Fade Demo'),
);
}
}
class MyFadeTest extends StatefulWidget {
const MyFadeTest({super.key, required this.title});
final String title;
@override
State<MyFadeTest> createState() => _MyFadeTest();
}
class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin {
late final AnimationController controller;
late final 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: FadeTransition(
opacity: curve,
child: const FlutterLogo(size: 100),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
controller.forward();
},
tooltip: 'Fade',
child: const Icon(Icons.brush),
),
);
}
}
詳細については、を参照してください。アニメーションとモーションのウィジェット、 のアニメーションのチュートリアル、 そしてそのアニメーションの概要。
画面上に描画/ペイントするにはどうすればよいですか?
Xamarin.Forms には、画面上に直接描画するための方法が組み込まれていませんでした。 カスタム画像を描画する必要がある場合、多くの人は SkiaSharp を使用するでしょう。 Flutter では、Skia Canvas に直接アクセスできます。 画面上に簡単に描画できます。
Flutter には、キャンバスへの描画に役立つ 2 つのクラスがあります。CustomPaint
とCustomPainter
後者は描画するアルゴリズムを実装します。
キャンバス。
Flutter で署名ペインタを実装する方法を学ぶには、 コリンの答えを参照してくださいカスタムペイント。
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: DemoApp()));
}
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) => const Scaffold(body: Signature());
}
class Signature extends StatefulWidget {
const Signature({super.key});
@override
SignatureState createState() => SignatureState();
}
class SignatureState extends State<Signature> {
List<Offset?> _points = <Offset?>[];
void _onPanUpdate(DragUpdateDetails details) {
setState(() {
final RenderBox referenceBox = context.findRenderObject() as RenderBox;
final Offset localPosition = referenceBox.globalToLocal(
details.globalPosition,
);
_points = List.from(_points)..add(localPosition);
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanUpdate: _onPanUpdate,
onPanEnd: (details) => _points.add(null),
child: CustomPaint(
painter: SignaturePainter(_points),
size: Size.infinite,
),
);
}
}
class SignaturePainter extends CustomPainter {
const SignaturePainter(this.points);
final List<Offset?> points;
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5;
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);
}
}
}
@override
bool shouldRepaint(SignaturePainter oldDelegate) =>
oldDelegate.points != points;
}
ウィジェットの不透明度はどこにありますか?
Xamarin.Forms では、すべてVisualElement
には不透明度があります。
Flutter では、ウィジェットをラップする必要があります。Opacity
ウィジェットこれを達成するために。
カスタム ウィジェットを作成するにはどうすればよいですか?
Xamarin.Forms では、通常、サブクラス化します。VisualElement
、
または既存のものを使用するVisualElement
、オーバーライドして、
望ましい動作を実現するメソッドを実装します。
Flutter では、次のようにカスタム ウィジェットを構築します。作曲する(ウィジェットを拡張する代わりに) より小さなウィジェットを作成します。
カスタム コントロールの実装に似ています。
に基づいてGrid
たくさんのVisualElement
が追加されました、
カスタムロジックで拡張しながら。
たとえば、どうやって構築しますかCustomButton
それはコンストラクターでラベルを受け取りますか?
を構成する CustomButton を作成します。ElevatedButton
拡張するのではなく、ラベルを使用してElevatedButton
:
class CustomButton extends StatelessWidget {
const CustomButton(this.label, {super.key});
final String label;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {},
child: Text(label),
);
}
}
次に、使用しますCustomButton
他の Flutter ウィジェットを使用するのと同じように、
@override
Widget build(BuildContext context) {
return const Center(
child: CustomButton('Hello'),
);
}
ナビゲーション
ページ間を移動するにはどうすればよいですか?
Xamarin.Forms では、NavigationPage
クラス
階層的なナビゲーション体験を提供します
ユーザーがページ間を移動できる場所、
前にも後ろにも。
Flutter にも同様の実装があります。
を使ってNavigator
とRoutes
。
あRoute
の抽象化ですPage
アプリの、
そしてNavigator
ですウィジェットルートを管理するものです。
ルートはおおよそ次のようにマッピングされます。Page
。
ナビゲーターは Xamarin.Forms と同様の方法で動作します。NavigationPage
、
それができるという点でpush()
とpop()
ルートに応じて
ビューに移動するか、ビューから戻るか。
ページ間を移動するには、いくつかのオプションがあります。
- を指定してください
Map
路線名のこと。 (MaterialApp
) - ルートに直接移動します。 (
WidgetsApp
)
次の例では、Map
。
void main() {
runApp(
MaterialApp(
home: const MyAppHome(), // becomes the route named '/'
routes: <String, WidgetBuilder>{
'/a': (context) => const MyPage(title: 'page A'),
'/b': (context) => const MyPage(title: 'page B'),
'/c': (context) => const MyPage(title: 'page C'),
},
),
);
}
ルート名をプッシュしてルートに移動します。Navigator
。
Navigator.of(context).pushNamed('/b');
のNavigator
アプリのルートを管理するスタックです。
ルートをスタックにプッシュすると、そのルートに移動します。
スタックからルートをポップすると、前のルートに戻ります。
これは、Future
によって返されましたpush()
。
async
/await
.NET 実装と非常によく似ています
でさらに詳しく説明されています非同期UI。
たとえば、location
ルート
ユーザーが自分の場所を選択できるようにするため、
次のようにすることもできます。
Object? coordinates = await Navigator.of(context).pushNamed('/location');
そして、「場所」ルート内で、ユーザーが自分の場所を選択すると、 場所を指定して、結果を含むスタックをポップします。
Navigator.of(context).pop({'lat': 43.821757, 'long': -79.226392});
別のアプリに移動するにはどうすればよいですか?
Xamarin.Forms でユーザーを別のアプリケーションに送信するには、
特定の URI スキームを使用する場合は、Device.OpenUrl("mailto://")
。
Flutter でこの機能を実装するには、
ネイティブ プラットフォーム統合を作成するか、既存のプラグイン、
そのようなurl_launcher
、他の多くのパッケージとともに利用可能パブ.dev。
非同期UI
Flutter の Device.BeginOnMainThread() に相当するものは何ですか?
Dart にはシングルスレッド実行モデルがあり、
のサポート付きIsolate
s (別のスレッドで Dart コードを実行する方法)、
イベントループと非同期プログラミング。
あなたがスポーンしない限り、7a864b9f-ecea-46e3-bc77-ec657bb41d2c、
Dart コードはメイン UI スレッドで実行されます
イベントループによって駆動されます。
Dart のシングルスレッド モデルは、すべてを実行する必要があるという意味ではありません
UI をフリーズさせるブロック操作として。
Xamarin.Forms と同様に、UI スレッドを解放しておく必要があります。
あなたなら使うでしょうasync
/await
タスクを実行するために、
応答を待つ必要があります。
Flutter では、Dart 言語が提供する非同期機能を使用します。
とも呼ばれますasync
/await
、非同期作業を実行します。
これは C# に非常に似ており、非常に使いやすいはずです。
すべての Xamarin.Forms 開発者向け。
たとえば、UI をハングさせることなくネットワーク コードを実行できます。
使用してasync
/await
そして、Dart に面倒な作業を任せます。
Future<void> loadData() async {
final Uri dataURL = Uri.parse(
'https://jsonplaceholder.typicode.com/posts',
);
final http.Response response = await http.get(dataURL);
setState(() {
data = jsonDecode(response.body);
});
}
待機されていたネットワーク呼び出しが完了すると、
呼び出して UI を更新するsetState()
、
これにより、ウィジェット サブツリーの再構築がトリガーされ、データが更新されます。
次の例では、データを非同期的にロードします。
そしてそれをListView
:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Map<String, dynamic>> data = <Map<String, dynamic>>[];
@override
void initState() {
super.initState();
loadData();
}
Future<void> loadData() async {
final Uri dataURL = Uri.parse(
'https://jsonplaceholder.typicode.com/posts',
);
final http.Response response = await http.get(dataURL);
setState(() {
data = jsonDecode(response.body);
});
}
Widget getRow(int index) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text('Row ${data[index]['title']}'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return getRow(index);
},
),
);
}
}
詳細については、次のセクションを参照してください バックグラウンドで作業を行う場合、 Flutter と Android の違いについて説明します。
作業をバックグラウンド スレッドに移動するにはどうすればよいでしょうか?
Flutterはシングルスレッドでイベントループを実行するため、
スレッド管理を気にする必要はありません
またはバックグラウンド スレッドを生成します。
これは Xamarin.Forms に非常に似ています。
ディスク アクセスやネットワーク呼び出しなど、I/O バウンドの作業を行っている場合は、
そうすれば安全に使用できますasync
/await
これで準備は完了です。
一方、計算集約的な作業を行う必要がある場合は、
CPU をビジー状態にし続けるため、
それをに移動したいのですが、Isolate
イベントループのブロックを避けるために、
あなたが保つようにどれでもメインスレッドから外れた一種の作業。
これは、物を別の場所に移動する場合と似ています。
スレッド経由Task.Run()
Xamarin.Forms で。
I/O バウンドの作業の場合は、関数を次のように宣言します。async
関数、
とawait
関数内の長時間実行タスクの場合:
Future<void> loadData() async {
final Uri dataURL = Uri.parse(
'https://jsonplaceholder.typicode.com/posts',
);
final http.Response response = await http.get(dataURL);
setState(() {
data = jsonDecode(response.body);
});
}
これは通常、ネットワークまたはデータベース呼び出しを行う方法です。 どちらも I/O 操作です。
ただし、処理している場合があります。
大量のデータがあり、UI がハングします。
Flutterでは、使用しますIsolate
複数の CPU コアを活用するため
長時間実行されるタスクや計算負荷の高いタスクを実行するため。
アイソレートは別個の実行スレッドです。
メイン実行メモリ ヒープとメモリを共有しません。
これは次の違いですTask.Run()
。
これは、メインスレッドから変数にアクセスできないことを意味します。
または呼び出して UI を更新しますsetState()
。
次の例は、単純な分離で次のことを示しています。 UI を更新するためにメインスレッドにデータを共有する方法。
Future<void> loadData() async {
final ReceivePort receivePort = ReceivePort();
await Isolate.spawn(dataLoader, receivePort.sendPort);
// The 'echo' isolate sends its SendPort as the first message
final SendPort sendPort = await receivePort.first as SendPort;
final List<Map<String, dynamic>> msg = await sendReceive(
sendPort,
'https://jsonplaceholder.typicode.com/posts',
);
setState(() {
data = msg;
});
}
// The entry point for the isolate
static Future<void> dataLoader(SendPort sendPort) async {
// Open the ReceivePort for incoming messages.
final ReceivePort port = ReceivePort();
// Notify any other isolates what port this isolate listens to.
sendPort.send(port.sendPort);
await for (final dynamic msg in port) {
final String url = msg[0] as String;
final SendPort replyTo = msg[1] as SendPort;
final Uri dataURL = Uri.parse(url);
final http.Response response = await http.get(dataURL);
// Lots of JSON to parse
replyTo.send(jsonDecode(response.body) as List<Map<String, dynamic>>);
}
}
Future<List<Map<String, dynamic>>> sendReceive(SendPort port, String msg) {
final ReceivePort response = ReceivePort();
port.send(<dynamic>[msg, response.sendPort]);
return response.first as Future<List<Map<String, dynamic>>>;
}
ここ、dataLoader()
それはIsolate
それが流れ込む
独自の別個の実行スレッド。
分離では、より多くの CPU を使用する実行が可能になります
処理 (大きな JSON の解析など)、
または、計算量の多い数学を実行する場合、
暗号化や信号処理など。
以下の完全な例を実行できます。
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Map<String, dynamic>> data = <Map<String, dynamic>>[];
@override
void initState() {
super.initState();
loadData();
}
bool get showLoadingDialog => data.isEmpty;
Future<void> loadData() async {
final ReceivePort receivePort = ReceivePort();
await Isolate.spawn(dataLoader, receivePort.sendPort);
// The 'echo' isolate sends its SendPort as the first message
final SendPort sendPort = await receivePort.first as SendPort;
final List<Map<String, dynamic>> msg = await sendReceive(
sendPort,
'https://jsonplaceholder.typicode.com/posts',
);
setState(() {
data = msg;
});
}
// The entry point for the isolate
static Future<void> dataLoader(SendPort sendPort) async {
// Open the ReceivePort for incoming messages.
final ReceivePort port = ReceivePort();
// Notify any other isolates what port this isolate listens to.
sendPort.send(port.sendPort);
await for (final dynamic msg in port) {
final String url = msg[0] as String;
final SendPort replyTo = msg[1] as SendPort;
final Uri dataURL = Uri.parse(url);
final http.Response response = await http.get(dataURL);
// Lots of JSON to parse
replyTo.send(jsonDecode(response.body) as List<Map<String, dynamic>>);
}
}
Future<List<Map<String, dynamic>>> sendReceive(SendPort port, String msg) {
final ReceivePort response = ReceivePort();
port.send(<dynamic>[msg, response.sendPort]);
return response.first as Future<List<Map<String, dynamic>>>;
}
Widget getBody() {
if (showLoadingDialog) {
return getProgressDialog();
}
return getListView();
}
Widget getProgressDialog() {
return const Center(child: CircularProgressIndicator());
}
ListView getListView() {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return getRow(index);
},
);
}
Widget getRow(int index) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text('Row ${data[index]['title']}'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: getBody(),
);
}
}
ネットワークリクエストを行うにはどうすればよいですか?
Xamarin.Forms では使用しますHttpClient
。
Flutter でネットワーク呼び出しを行うのは簡単です
人気のものを使うときはhttp
パッケージ。
これにより、ネットワークの多くが抽象化されます。
通常は自分で実装するかもしれませんが、
ネットワーク通話が簡単になります。
を使用するには、http
パッケージにある場合は、それを依存関係に追加しますpubspec.yaml
:
dependencies:
http: ^1.0.0
ネットワークリクエストを行うには、
電話await
でasync
関数http.get()
:
Future<void> loadData() async {
final Uri dataURL = Uri.parse(
'https://jsonplaceholder.typicode.com/posts',
);
final http.Response response = await http.get(dataURL);
setState(() {
data = jsonDecode(response.body);
});
}
長時間実行されるタスクの進行状況を表示するにはどうすればよいですか?
Xamarin.Forms では通常、読み込みインジケーターを作成します。 XAML で直接、または AcrDialogs などのサードパーティのプラグインを介して。
Flutter では、ProgressIndicator
ウィジェット。
プログラムで制御して進行状況を表示する
ブール値フラグを介してレンダリングされるとき。
長時間実行されるタスクが開始される前に状態を更新するように Flutter に指示します。
そして終了後は非表示にします。
以下の例では、ビルド関数が 3 つの異なる関数に分かれています。
機能。もしもshowLoadingDialog
はtrue
(いつwidgets.length == 0
)、レンダリングします。ProgressIndicator
。
それ以外の場合は、レンダリングListView
ネットワーク呼び出しから返されたデータを使用します。
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Map<String, dynamic>> data = <Map<String, dynamic>>[];
@override
void initState() {
super.initState();
loadData();
}
bool get showLoadingDialog => data.isEmpty;
Future<void> loadData() async {
final Uri dataURL = Uri.parse(
'https://jsonplaceholder.typicode.com/posts',
);
final http.Response response = await http.get(dataURL);
setState(() {
data = jsonDecode(response.body);
});
}
Widget getBody() {
if (showLoadingDialog) {
return getProgressDialog();
}
return getListView();
}
Widget getProgressDialog() {
return const Center(child: CircularProgressIndicator());
}
ListView getListView() {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return getRow(index);
},
);
}
Widget getRow(int index) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text('Row ${data[index]['title']}'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: getBody(),
);
}
}
プロジェクトの構造とリソース
画像ファイルはどこに保存すればよいですか?
Xamarin.Forms にはプラットフォームに依存しない画像の保存方法がありません。
iOS に画像を配置する必要がありましたxcasset
フォルダ、
または Android のさまざまなdrawable
フォルダー。
Android と iOS はリソースとアセットを別個のアイテムとして扱いますが、
Flutter アプリにはアセットのみがあります。
に存在するすべてのリソースResources/drawable-*
Android 上のフォルダー、
Flutter のアセットフォルダーに配置されます。
Flutter は、iOS のような単純な密度ベースの形式に従います。
資産は次のとおりである可能性があります1.0x
、2.0x
、3.0x
、またはその他の乗数。
flutterにはありませんdp
論理ピクセルはありますが、
これは基本的にデバイスに依存しないピクセルと同じです。
flutterズdevicePixelRatio
比率を表します
単一の論理ピクセル内の物理ピクセルの数。
Android の密度バケットに相当するものは次のとおりです。
Android 密度修飾子 | flutterピクセル率 |
---|---|
ldpi |
0.75x |
mdpi |
1.0x |
hdpi |
1.5x |
xhdpi |
2.0x |
xxhdpi |
3.0x |
xxxhdpi |
4.0x |
アセットは任意のフォルダーにあります。
Flutter には事前定義されたフォルダー構造はありません。
資産を(場所とともに)申告します。
の中にpubspec.yaml
ファイルを開くと、Flutter がそれらを取得します。
という新しい画像アセットを追加するには、my_icon.png
Flutter プロジェクトに、
たとえば、フォルダーに保存する必要があると判断した場合、
勝手に呼ばれるimages
、ベース画像 (1.0x) を配置します。
の中にimages
フォルダー、およびサブフォルダー内の他のすべてのバリアント
適切な比率乗数を使用して呼び出されます。
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
画像に直接アクセスできます。Image.asset
ウィジェット:
@override
Widget build(BuildContext context) {
return Image.asset('images/my_icon.png');
}
または使用してAssetImage
:
@override
Widget build(BuildContext context) {
return const Image(
image: AssetImage('images/my_image.png'),
);
}
さらに詳しい情報は、アセットと画像の追加。
文字列はどこに保存すればよいですか?ローカリゼーションはどのように処理すればよいですか?
.NET とは異なり、resx
ファイル、
Flutter には現在、文字列を処理するための専用システムがありません。
現時点でのベストプラクティスは、コピーテキストを宣言することです。
クラス内で静的フィールドとして保存し、そこからアクセスします。例えば:
class Strings {
static const String welcomeMessage = 'Welcome To Flutter';
}
次のようにして文字列にアクセスできます。
Text(Strings.welcomeMessage);
デフォルトでは、Flutter は文字列として米国英語のみをサポートします。
他の言語のサポートを追加する必要がある場合は、
を含むflutter_localizations
パッケージ。
ダーツを追加する必要がある場合もありますintl
日付/時刻のフォーマットなど、i10n 機構を使用するためのパッケージ。
dependencies:
flutter_localizations:
sdk: flutter
intl: '^0.17.0'
を使用するには、flutter_localizations
パッケージ、
を指定しますlocalizationsDelegates
とsupportedLocales
アプリのウィジェットで:
import 'package:flutter_localizations/flutter_localizations.dart';
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
// Add app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: <Locale>[
Locale('en', 'US'), // English
Locale('he', 'IL'), // Hebrew
// ... other locales the app supports
],
);
}
}
デリゲートには実際のローカライズされた値が含まれています。
一方supportedLocales
アプリがサポートするロケールを定義します。
上記の例では、MaterialApp
、
したがって、それは両方を持っていますGlobalWidgetsLocalizations
ベースウィジェットのローカライズされた値の場合、
そしてMaterialWidgetsLocalizations
マテリアル ウィジェットのローカリゼーション用。
使用する場合WidgetsApp
あなたのアプリでは後者は必要ありません。
これら 2 つのデリゲートには「デフォルト」値が含まれていることに注意してください。
ただし、1 人以上の代理人を指定する必要があります
独自のアプリのローカライズ可能なコピーの場合、
それらもローカライズしたい場合。
初期化すると、WidgetsApp
(またMaterialApp
)
を作成しますLocalizations
あなたのためのウィジェット、
あなたが指定した代理人と一緒に。
デバイスの現在のロケールには常にアクセスできます
からLocalizations
現在のコンテキストからのウィジェット
(の形で)Locale
オブジェクト)、またはWindow.locale
。
ローカライズされたリソースにアクセスするには、Localizations.of()
方法
特定のデリゲートによって提供される特定のローカリゼーション クラスにアクセスします。
使用intl_translation
翻訳可能なコピーを抽出するためのパッケージ
にアーブファイルを翻訳してアプリにインポートし直す
一緒に使用するためintl
。
Flutter の国際化とローカリゼーションの詳細については、
を参照してください国際化ガイド、サンプルコードがあります
ありとなしintl
パッケージ。
私のプロジェクトファイルはどこにありますか?
Xamarin.Forms には、csproj
ファイル。
Flutter で最も近いものは pubspec.yaml です。
これには、パッケージの依存関係とさまざまなプロジェクトの詳細が含まれます。
.NET Standard と同様に、
同じディレクトリ内のファイルはプロジェクトの一部とみなされます。
Nuget に相当するものは何ですか?依存関係を追加するにはどうすればよいですか?
.NET エコシステムでは、ネイティブ Xamarin プロジェクトと Xamarin.Forms プロジェクト Nuget と組み込みのパッケージ管理システムにアクセスできました。 Flutter アプリには、ネイティブ Android アプリ、ネイティブ iOS アプリ、および Flutter アプリが含まれています。
Android では、Gradle ビルド スクリプトに追加することで依存関係を追加します。
iOS では、依存関係を追加するには、Podfile
。
Flutter は、Dart 独自のビルド システムと Pub パッケージ マネージャーを使用します。 このツールは、Android および iOS のネイティブ ラッパー アプリの構築を委任します。 それぞれのビルド システムに適用されます。
一般に、使用しますpubspec.yaml
宣言する
Flutter で使用する外部依存関係。
Flutter パッケージを見つけるのに適した場所は次のとおりです。パブ.dev。
アプリケーションのライフサイクル
アプリケーションのライフサイクル イベントをリッスンするにはどうすればよいですか?
Xamarin.Forms には、Application
含まれているOnStart
、OnResume
とOnSleep
。
Flutter では、代わりに同様のライフサイクル イベントをリッスンできます。
に引っ掛けることでWidgetsBinding
観察者と聞く者
のdidChangeAppLifecycleState()
変更イベント。
監視可能なライフサイクル イベントは次のとおりです。
inactive
- アプリケーションは非アクティブ状態にあり、ユーザー入力を受け付けていません。 このイベントはiOSのみです。
paused
- アプリケーションは現在ユーザーには表示されませんが、 ユーザー入力に応答せず、バックグラウンドで実行されています。
- 19d196a1-cd55-4473-8d2b-b457e4214d1e
- アプリケーションは表示され、ユーザー入力に応答します。
suspending
- アプリケーションは一時停止されています。 本イベントはAndroidのみとなります。
これらの状態の意味の詳細については、
を参照してくださいAppLifecycleStatus
ドキュメンテーション。
レイアウト
StackLayout に相当するものは何ですか?
Xamarin.Forms では、StackLayout
とOrientation
水平か垂直か。
Flutter にも同様のアプローチがあります。
ただし、使用するのはRow
またColumn
ウィジェット。
2 つのコード サンプルが同一であることに気付いた場合は、
を除いてRow
とColumn
ウィジェット。
子供たちも同じで、この機能は
リッチなレイアウトを開発するために活用できます
同じ子供でも残業時間は変わる可能性があります。
@override
Widget build(BuildContext context) {
return const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Row One'),
Text('Row Two'),
Text('Row Three'),
Text('Row Four'),
],
);
}
@override
Widget build(BuildContext context) {
return const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Column One'),
Text('Column Two'),
Text('Column Three'),
Text('Column Four'),
],
);
グリッドに相当するものは何ですか?
に最も近い同等のものGrid
だろうGridView
。
これは、Xamarin.Forms で使用しているものよりもはるかに強力です。
あGridView
自動スクロールを提供します。
コンテンツが表示可能なスペースを超えています。
@override
Widget build(BuildContext context) {
return GridView.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) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headlineMedium,
),
);
},
),
);
}
を使用したことがあるかもしれませんGrid
Xamarin.Forms 内
他のウィジェットをオーバーレイするウィジェットを実装します。
Flutter では、これを次のように実行します。Stack
ウィジェット。
このサンプルでは、互いに重なる 2 つのアイコンを作成します。
@override
Widget build(BuildContext context) {
return const Stack(
children: <Widget>[
Icon(
Icons.add_box,
size: 24,
color: Colors.black,
),
Positioned(
left: 10,
child: Icon(
Icons.add_circle,
size: 24,
color: Colors.black,
),
),
],
);
}
ScrollView に相当するものは何ですか?
Xamarin.Forms では、ScrollView
を包み込むVisualElement
、
コンテンツがデバイスの画面より大きい場合は、スクロールします。
Flutter では、最も近い一致はSingleChildScrollView
ウィジェット。
スクロール可能にしたいコンテンツをウィジェットに入力するだけです。
@override
Widget build(BuildContext context) {
return const SingleChildScrollView(
child: Text('Long Content'),
);
}
巻物に包みたいものがたくさんある場合は、
たとえ違うものであってもWidget
型の場合は、ListView
。
これはやりすぎのように思えるかもしれませんが、Flutter ではこれは次のとおりです。
Xamarin.Forms よりもはるかに最適化されており、負荷が低くなります。ListView
、
これはプラットフォーム固有のコントロールに戻ります。
@override
Widget build(BuildContext context) {
return ListView(
children: const <Widget>[
Text('Row One'),
Text('Row Two'),
Text('Row Three'),
Text('Row Four'),
],
);
}
Flutter でランドスケープの遷移を処理するにはどうすればよいですか?
風景の遷移は、configChanges
AndroidManifest.xml のプロパティ:
<activity android:configChanges="orientation|screenSize" />
ジェスチャー検出とタッチイベント処理
Flutter のウィジェットに GestureRecognizer を追加するにはどうすればよいですか?
Xamarin.Forms では、Element
には、アタッチできるクリック イベントが含まれる場合があります。
多くの要素には、Command
それが今回のイベントに繋がっています。
あるいは、TapGestureRecognizer
。
Flutter には、よく似た 2 つの方法があります。
-
ウィジェットがイベント検出をサポートしている場合は、ウィジェットに関数を渡して、 関数内で処理します。たとえば、ElevatedButton には
onPressed
パラメータ:@override Widget build(BuildContext context) { return ElevatedButton( onPressed: () { developer.log('click'); }, child: const Text('Button'), ); }
-
ウィジェットがイベント検出をサポートしていない場合は、 のウィジェット
GestureDetector
そして関数を渡します にonTap
パラメータ。class SampleApp extends StatelessWidget { const SampleApp({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( onTap: () { developer.log('tap'); }, child: const FlutterLogo(size: 200), ), ), ); } }
ウィジェット上で他のジェスチャを処理するにはどうすればよいですか?
Xamarin.Forms では、GestureRecognizer
にView
。
通常は次のように制限されます。TapGestureRecognizer
、PinchGestureRecognizer
、PanGestureRecognizer
、SwipeGestureRecognizer
、DragGestureRecognizer
とDropGestureRecognizer
自分で構築した場合を除きます。
Flutter では、GestureDetector を使用して、 次のような幅広いジェスチャを聞くことができます。
- タップ
onTapDown
- タップを引き起こす可能性のあるポインター 特定の場所で画面に接触しました。
onTapUp
- タップをトリガーするポインター 特定の場所で画面との接触が停止しました。
onTap
- タップが発生しました。
onTapCancel
- 以前にトリガーしたポインター
onTapDown
タップの原因にはなりません。
- ダブルタップ
onDoubleTap
- ユーザーが画面の同じ場所を 2 回タップしました 立て続けに。
- 長押し
onLongPress
- ポインターが画面に触れたままになっている 長時間同じ場所にいること。
- 垂直方向のドラッグ
onVerticalDragStart
- ポインタが画面に触れて垂直に動き始める可能性があります。
onVerticalDragUpdate
- 画面に接触しているポインタ さらに垂直方向に移動しました。
onVerticalDragEnd
- 以前に接触していたポインタ 画面と垂直方向の移動が接触しなくなりました 画面とともに特定の速度で移動していた 画面に接触しなくなったとき。
- 水平方向のドラッグ
onHorizontalDragStart
- ポインタが画面に触れて水平に動き始める可能性があります。
onHorizontalDragUpdate
- 画面に接触しているポインタ さらに水平方向に移動しました。
onHorizontalDragEnd
- 以前に接触していたポインタ 画面と水平移動が接触しなくなりました 画面とともに特定の速度で移動していた 画面に接触しなくなったとき。
次の例は、GestureDetector
ダブルタップで Flutter ロゴを回転させます。
class RotatingFlutterDetector extends StatefulWidget {
const RotatingFlutterDetector({super.key});
@override
State<RotatingFlutterDetector> createState() =>
_RotatingFlutterDetectorState();
}
class _RotatingFlutterDetectorState extends State<RotatingFlutterDetector>
with SingleTickerProviderStateMixin {
late final AnimationController controller;
late final 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(
body: Center(
child: GestureDetector(
onDoubleTap: () {
if (controller.isCompleted) {
controller.reverse();
} else {
controller.forward();
}
},
child: RotationTransition(
turns: curve,
child: const FlutterLogo(size: 200),
),
),
),
);
}
}
リストビューとアダプター
Flutter の ListView に相当するものは何ですか?
と同等のものListView
Flutter では…ListView
!
Xamarin.Forms 内ListView
を作成すると、ViewCell
そしておそらくDataTemplateSelector
それをに渡しますListView
、
これは各行をあなたのものでレンダリングしますDataTemplateSelector
またViewCell
戻り値。
ただし、多くの場合、セルのリサイクルを必ずオンにする必要があります。
そうしないと、メモリの問題が発生し、スクロール速度が遅くなります。
Flutter の不変ウィジェット パターンにより、
ウィジェットのリストをListView
、
Flutter はスクロールが高速かつスムーズであることを保証します。
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatelessWidget {
const SampleAppPage({super.key});
List<Widget> _getListData() {
return List<Widget>.generate(
100,
(index) => Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $index'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: ListView(children: _getListData()),
);
}
}
どのリスト項目がクリックされたかを確認するにはどうすればよいですか?
Xamarin.Forms では、ListView にはItemTapped
方法
どの項目がクリックされたかを確認します。
他にも使用した可能性のあるテクニックはたくさんあります
いつチェックするかなどSelectedItem
またEventToCommand
行動が変わります。
Flutter では、渡されたウィジェットによって提供されるタッチ処理を使用します。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> _getListData() {
return List<Widget>.generate(
100,
(index) => GestureDetector(
onTap: () {
developer.log('Row $index tapped');
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $index'),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: ListView(children: _getListData()),
);
}
}
ListView を動的に更新するにはどうすればよいですか?
Xamarin.Forms で、ItemsSource
プロパティをObservableCollection
、
ViewModel 内のリストを更新するだけです。
あるいは、新しいものを割り当てることもできます。List
にItemSource
財産。
Flutter では、動作が少し異なります。
内のウィジェットのリストを更新すると、setState()
方法、
データが視覚的に変化していないことがすぐにわかります。
なぜなら、いつsetState()
と呼ばれます、
Flutter レンダリング エンジンはウィジェット ツリーを確認します。
何かが変わったかどうかを確認します。
それがあなたの手元に届いたら、ListView
を実行します。==
チェック、
そして、その2つがListView
も同じです。
何も変更されていないため、更新する必要はありません。
を更新する簡単な方法については、ListView
、
新しいを作成しますList
の中にsetState()
、
古いリストから新しいリストにデータをコピーします。
このアプローチはシンプルですが、大規模なデータセットには推奨されません。
次の例に示すように。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> widgets = <Widget>[];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
Widget getRow(int index) {
return GestureDetector(
onTap: () {
setState(() {
widgets = List<Widget>.from(widgets);
widgets.add(getRow(widgets.length));
developer.log('Row $index');
});
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $index'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: ListView(children: widgets),
);
}
}
リストを作成するための推奨される効率的かつ効果的な方法
を使用しますListView.Builder
。
この方法は、動的リストがある場合に最適です
または非常に大量のデータを含むリスト。
これは本質的に Android の RecyclerView と同等です。
これにより、リスト要素が自動的にリサイクルされます。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
Widget getRow(int index) {
return GestureDetector(
onTap: () {
setState(() {
widgets.add(getRow(widgets.length));
developer.log('Row $index');
});
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $index'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, index) {
return getRow(index);
},
),
);
}
}
を作成する代わりに、ListView
を作成します。ListView.builder
これは 2 つの重要なパラメータを取ります: リストの初期長、
そしてアイテムビルダー機能。
アイテムビルダー関数は次のようなものです。getView
関数
Android アダプター内。それは位置をとり、
そして、その位置にレンダリングしたい行を返します。
最後に、しかし最も重要なことですが、onTap()
関数
リストを再作成するのではなく、リストに追加します。
詳細については、を参照してください。初めての Flutter アプリコードラボ。
テキストの操作
テキスト ウィジェットにカスタム フォントを設定するにはどうすればよいですか?
Xamarin.Forms では、各ネイティブ プロジェクトにカスタム フォントを追加する必要があります。
次に、あなたの中でElement
このフォント名を割り当てます
にFontFamily
属性を使用するfilename#fontname
そしてちょうどfontname
iOS用。
Flutterではフォントファイルをフォルダに置いて参照します
の中にpubspec.yaml
画像をインポートする方法と同様に、ファイルを作成します。
fonts:
- family: MyCustomFont
fonts:
- asset: fonts/MyCustomFont.ttf
- style: italic
次にフォントをText
ウィジェット:
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Sample App')),
body: const Center(
child: Text(
'This is a custom font text',
style: TextStyle(fontFamily: 'MyCustomFont'),
),
),
);
}
テキスト ウィジェットのスタイルを設定するにはどうすればよいですか?
フォントに加えて、他のスタイル要素もカスタマイズできます。Text
ウィジェット。
のスタイルパラメータText
ウィジェットはTextStyle
物体、
ここでは、次のような多くのパラメータをカスタマイズできます。
color
decoration
decorationColor
decorationStyle
fontFamily
fontSize
fontStyle
fontWeight
hashCode
height
inherit
letterSpacing
textBaseline
wordSpacing
フォーム入力
ユーザー入力を取得するにはどうすればよいですか?
Xamarin.Formselement
を直接クエリできるようになります。element
そのプロパティの状態を判断するには、
または、それがプロパティにバインドされているかどうかViewModel
。
Flutter での情報の取得は特殊なウィジェットによって処理されます
そして、あなたが慣れているやり方とは異なります。
持っている場合は、TextField
またはTextFormField
、
を供給できますTextEditingController
ユーザー入力を取得するには:
import 'package:flutter/material.dart';
class MyForm extends StatefulWidget {
const MyForm({super.key});
@override
State<MyForm> createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
/// Create a text controller and use it to retrieve the current value
/// of the TextField.
final TextEditingController myController = TextEditingController();
@override
void dispose() {
// Clean up the controller when disposing of the widget.
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Retrieve Text Input')),
body: Padding(
padding: const EdgeInsets.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) {
return AlertDialog(
// Retrieve the text that the user has entered using the
// TextEditingController.
content: Text(myController.text),
);
},
);
},
tooltip: 'Show me the value!',
child: const Icon(Icons.text_fields),
),
);
}
}
詳細と完全なコードのリストは、次の場所にあります。テキストフィールドの値を取得する、 から flutterクックブック。
エントリのプレースホルダーに相当するものは何ですか?
Xamarin.Forms では、いくつかのElements
をサポートするPlaceholder
財産
値を割り当てることができます。例えば:
<Entry Placeholder="This is a hint">
Flutter では、「ヒント」またはプレースホルダー テキストを簡単に表示できます
を追加して入力してくださいInputDecoration
物体
にdecoration
テキスト ウィジェットのコンストラクター パラメーター。
TextField(
decoration: InputDecoration(hintText: 'This is a hint'),
),
検証エラーを表示するにはどうすればよいですか?
Xamarin.Forms を使用して、視覚的なヒントを提供したい場合は、
検証エラーが発生した場合は、新しいプロパティを作成する必要があります。VisualElement
を囲んでいるElement
検証エラーがあった。
Flutter では、InputDecoration オブジェクトを介して テキスト ウィジェットの装飾コンストラクター。
ただし、最初からエラーを表示することは望ましくありません。
代わりに、ユーザーが無効なデータを入力した場合、
状態を更新し、新しい値を渡しますInputDecoration
物体。
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Sample App',
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
String? _errorText;
String? _getErrorText() {
return _errorText;
}
bool isEmail(String em) {
const String emailRegexp =
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,}))$';
final RegExp regExp = RegExp(emailRegexp);
return regExp.hasMatch(em);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('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プラグイン
ハードウェア、サードパーティのサービス、およびプラットフォームとの対話
プラットフォームおよびプラットフォームのネイティブ コードと対話するにはどうすればよいですか?
Flutter は、基盤となるプラットフォーム上でコードを直接実行しません。
むしろ、Flutter アプリを構成する Dart コードはネイティブに実行されます。
デバイス上で、プラットフォームによって提供される SDK を「回避」します。
つまり、たとえば、Dart でネットワーク リクエストを実行すると、
Dart コンテキストで直接実行されます。
Android または iOS API を使用しない
通常、ネイティブ アプリを作成するときに利用します。
Flutter アプリは引き続きネイティブ アプリでホストされていますViewController
またActivity
見方としては、
ただし、これやネイティブ フレームワークに直接アクセスすることはできません。
これは、Flutter アプリがこれらのネイティブ API と対話できないという意味ではありません。
または、お持ちのネイティブ コードを使用して実行することもできます。 Flutter が提供するプラットフォームチャネルと通信し、データを交換するViewController
またActivity
Flutter ビューをホストします。
プラットフォーム チャネルは本質的には非同期メッセージング メカニズムです
Dart コードとホストをブリッジします。ViewController
またActivity
およびそれが実行される iOS または Android フレームワーク。
プラットフォーム チャネルを使用してネイティブ側でメソッドを実行できます。
たとえば、デバイスのセンサーからデータを取得することもできます。
プラットフォーム チャネルを直接使用することに加えて、 さまざまな既製のものを使用できますプラグイン特定の目的のためにネイティブ コードと Dart コードをカプセル化します。 たとえば、プラグインを使用してアクセスできます。 カメラ ロールとデバイスのカメラを Flutter から直接、 独自の統合を作成する必要はありません。 プラグインは次の場所にありますパブ.dev、 Dart と Flutter のオープンソース パッケージ リポジトリ。 一部のパッケージは iOS でのネイティブ統合をサポートしている場合があります。 または Android、あるいはその両方。
pub.dev でニーズに合ったプラグインが見つからない場合は、 あなたはできる自分で書いてください、 とpub.dev で公開します。
GPS センサーにアクセスするにはどうすればよいですか?
使用geolocator
コミュニティプラグイン。
カメラにアクセスするにはどうすればよいですか?
のcamera
プラグインはカメラにアクセスするためによく使用されます。
Facebook にログインするにはどうすればよいですか?
Facebook でログインするには、flutter_facebook_login
コミュニティプラグイン。
Firebase の機能を使用するにはどうすればよいですか?
Firebase のほとんどの機能は以下でカバーされています。ファーストパーティのプラグイン。 これらのプラグインはファーストパーティの統合であり、Flutter チームによって維持されています。
-
firebase_admob
Firebase AdMob 用 -
firebase_analytics
Firebase アナリティクス用 -
firebase_auth
Firebase認証の場合 -
firebase_database
Firebase RTDB 用 -
firebase_storage
Firebaseクラウドストレージ用 -
firebase_messaging
Firebase メッセージング (FCM) 用 -
flutter_firebase_ui
Firebase Auth 統合を迅速に行うため (Facebook、Google、Twitter、電子メール) -
cloud_firestore
Firebase クラウド Firestore 用
pub.dev では、サードパーティの Firebase プラグインもいくつか見つけることができます。 ファーストパーティのプラグインが直接カバーしていない領域をカバーします。
独自のカスタム ネイティブ統合を構築するにはどうすればよいですか?
Flutter が実行するプラットフォーム固有の機能がある場合 またはコミュニティプラグインが見つからない、 次のように独自のものを構築できますパッケージとプラグインの開発ページ。
Flutter のプラグイン アーキテクチャを一言で言うと、 Android でのイベント バスの使用によく似ています。 メッセージを送信し、受信者に結果を処理させて出力させます。 あなたに戻って。この場合、受信側はネイティブ側で実行されるコードです。 Android または iOS で。
テーマ (スタイル)
アプリのテーマを設定するにはどうすればよいですか?
Flutter には、マテリアル デザインの美しい組み込み実装が付属しています。 スタイルとテーマのニーズの多くを処理します 通常はそうするでしょう。
Xamarin.Forms にはグローバルがありますResourceDictionary
アプリ全体でスタイルを共有できます。
あるいは、現在プレビュー中のテーマのサポートもあります。
Flutter では、トップレベルのウィジェットでテーマを宣言します。
アプリでマテリアル コンポーネントを最大限に活用するには、
最上位のウィジェットを宣言できますMaterialApp
アプリケーションへのエントリ ポイントとして。MaterialApp
便利なウィジェットです
一般に必要な多数のウィジェットをラップします
マテリアル デザインを実装するアプリケーション向け。
それは、WidgetsApp
マテリアル固有の機能を追加することによって。
を使用することもできますWidgetsApp
アプリのウィジェットとして、
同じ機能の一部を提供しますが、
しかし、それほど裕福ではありませんMaterialApp
。
子コンポーネントの色とスタイルをカスタマイズするには、
渡すThemeData
に反対するMaterialApp
ウィジェット。
たとえば、次のコードでは、
プライマリ スウォッチは青に設定され、テキスト選択の色は赤に設定されます。
class SampleApp extends StatelessWidget {
/// This widget is the root of your application.
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
textSelectionTheme:
const TextSelectionThemeData(selectionColor: Colors.red),
),
home: const SampleAppPage(),
);
}
}
データベースとローカルストレージ
共有設定または UserDefaults にアクセスするにはどうすればよいですか?
Xamarin.Forms 開発者はおそらくよく知っているでしょう。Xam.Plugins.Settings
プラグイン。
Flutter では、以下を使用して同等の機能にアクセスします。shared_preferences
プラグイン。このプラグインは
両方の機能UserDefaults
そしてアンドロイド
同等、SharedPreferences
。
Flutter で SQLite にアクセスするにはどうすればよいですか?
Xamarin.Forms では、ほとんどのアプリケーションはsqlite-net-pcl
SQLite データベースにアクセスするためのプラグイン。
Flutter では、次のコマンドを使用してこの機能にアクセスします。sqflite
プラグイン。
デバッグ
Flutter でアプリをデバッグするにはどのようなツールを使用できますか?
使用開発ツールFlutter または Dart アプリをデバッグするためのスイート。
DevTools には、プロファイリング、ヒープの検査、 ウィジェット ツリーの検査、診断のログ記録、デバッグ、 実行されたコード行を観察し、 メモリ リークとメモリの断片化をデバッグします。 詳細については、「開発ツールドキュメンテーション。
通知
プッシュ通知を設定するにはどうすればよいですか?
Android では、Firebase Cloud Messaging を使用してセットアップします アプリのプッシュ通知。
Flutter では、次のコマンドを使用してこの機能にアクセスします。firebase_messaging
プラグイン。
Firebase Cloud Messaging API の使用方法の詳細については、firebase_messaging
プラグインのドキュメント。