<
コンテンツ

React Native 開発者向けの Flutter

コンテンツ

このドキュメントは、React Native (RN) の適用を検討している開発者を対象としています。 Flutter を使用してモバイル アプリを構築するための既存の RN 知識。もし分かれば RN フレームワークの基礎を理解している場合は、このドキュメントを次の資料として使用できます。 Flutter 開発の学習を始める方法。

このドキュメントは、あちこちに移動して見つけてクックブックとして使用できます。 あなたのニーズに最も関連する質問。

JavaScript 開発者のための Dart の概要 (ES6)

React Native と同様に、Flutter はリアクティブ スタイルのビューを使用します。ただし、RN である一方で、 Flutter はネイティブ ウィジェットにトランスパイルされ、ネイティブ コードまでコンパイルされます。 Flutter は画面上の各ピクセルを制御し、パフォーマンスの問題を回避します。 これは JavaScript ブリッジが必要なために発生します。

Dart は習得が簡単な言語で、次の機能を備えています。

  • Web を構築するためのオープンソースのスケーラブルなプログラミング言語を提供します。 サーバーとモバイルアプリ。
  • C スタイルを使用するオブジェクト指向の単一継承言語を提供します。 AOT によってネイティブにコンパイルされた構文。
  • オプションで JavaScript にトランスコンパイルします。
  • インターフェイスと抽象クラスをサポートします。

JavaScript と Dart の違いの例をいくつか説明します。 下。

エントリーポイント

JavaScript には事前定義されたエントリがありません 関数 - エントリ ポイントを定義します。

// JavaScript
function startHere() {
  // Can be used as entry point
}

Dart では、すべてのアプリにトップレベルが必要ですmain()として機能する関数 アプリへのエントリポイント。

/// Dart
void main() {}

で試してみてくださいダーツパッド。

コンソールへの印刷

Dart でコンソールに出力するには、次を使用します。print()

// JavaScript
console.log('Hello world!');
/// Dart
print('Hello world!');

で試してみてくださいダーツパッド。

変数

Dart はタイプセーフです。静的な型チェックを組み合わせて使用​​します。 変数の値が常に一致することを確認する実行時チェック 変数の静的型。種類は必須ですが、 一部の型アノテーションはオプションです。 Dart は型推論を実行します。

変数の作成と割り当て

JavaScript では変数を型指定できません。

のダーツ、変数は明示的に 型付けされていないか、型システムが適切な型を自動的に推測する必要があります。

// JavaScript
let name = 'JavaScript';
/// Dart
/// Both variables are acceptable.
String name = 'dart'; // Explicitly typed as a [String].
var otherName = 'Dart'; // Inferred [String] type.

で試してみてくださいダーツパッド。

詳細については、を参照してください。ダーツのタイプシステム。

デフォルト値

JavaScript では、初期化されていない変数は次のとおりです。undefined

Dart では、初期化されていない変数の初期値は次のとおりです。null。 Dart では数値はオブジェクトであるため、初期化されていない変数であっても、 数値型には値がありますnull

// JavaScript
let name; // == undefined
// Dart
var name; // == null; raises a linter warning
int? x; // == null

で試してみてくださいダーツパッド。

詳細については、次のドキュメントを参照してください。変数。

null またはゼロのチェック

JavaScript では、値 1 または null 以外のオブジェクト として扱われますtrueを使用するとき==比較演算子。

// JavaScript
let myNull = null;
if (!myNull) {
  console.log('null is treated as false');
}
let zero = 0;
if (!zero) {
  console.log('0 is treated as false');
}

Dart ではブール値のみtrueは真として扱われます。

/// Dart
var myNull;
var zero = 0;
if (zero == 0) {
  print('use "== 0" to check zero');
}

で試してみてくださいダーツパッド。

機能

Dart と JavaScript の関数は一般的に似ています。 主な違いは宣言です。

// JavaScript
function fn() {
  return true;
}
/// Dart
/// You can explicitly define the return type.
bool fn() {
  return true;
}

で試してみてくださいダーツパッド。

詳細については、次のドキュメントを参照してください。機能。

非同期プログラミング

先物

JavaScript と同様に、Dart はシングルスレッド実行をサポートしています。 JavaScriptでは、 Promise オブジェクトは最終的な完了 (または失敗) を表します。 非同期操作とその結果の値。

ダーツの使い方Futureこれを処理するオブジェクト。

// JavaScript
class Example {
  _getIPAddress() {
    const url = 'https://httpbin.org/ip';
    return fetch(url)
      .then(response => response.json())
      .then(responseJson => {
        const ip = responseJson.origin;
        return ip;
      });
  }
}

function main() {
  const example = new Example();
  example
    ._getIPAddress()
    .then(ip => console.log(ip))
    .catch(error => console.error(error));
}

main();
/// Dart
import 'dart:convert';

import 'package:http/http.dart' as http;

class Example {
  Future<String> _getIPAddress() {
    final url = Uri.https('httpbin.org', '/ip');
    return http.get(url).then((response) {
      String ip = jsonDecode(response.body)['origin'];
      return ip;
    });
  }
}

void main() {
  final example = Example();
  example
      ._getIPAddress()
      .then((ip) => print(ip))
      .catchError((error) => print(error));
}

詳細については、次のドキュメントを参照してください。Futureオブジェクト。

asyncawait

async関数宣言は非同期関数を定義します。

JavaScript では、async関数は次の値を返しますPromise。 のawait演算子は待機するために使用されます。Promise

// JavaScript
class Example {
  async function _getIPAddress() {
    const url = 'https://httpbin.org/ip';
    const response = await fetch(url);
    const json = await response.json();
    const data = json.origin;
    return data;
  }
}

async function main() {
  const example = new Example();
  try {
    const ip = await example._getIPAddress();
    console.log(ip);
  } catch (error) {
    console.error(error);
  }
}

main();

ダーツでは、async関数は次の値を返しますFuture、 関数の本体は後で実行されるようにスケジュールされます。 のawait演算子は待機するために使用されます。Future

// Dart
import 'dart:convert';

import 'package:http/http.dart' as http;

class Example {
  Future<String> _getIPAddress() async {
    final url = Uri.https('httpbin.org', '/ip');
    final response = await http.get(url);
    String ip = jsonDecode(response.body)['origin'];
    return ip;
  }
}

/// An async function returns a `Future`.
/// It can also return `void`, unless you use
/// the `avoid_void_async` lint. In that case,
/// return `Future<void>`.
void main() async {
  final example = Example();
  try {
    final ip = await example._getIPAddress();
    print(ip);
  } catch (error) {
    print(error);
  }
}

詳細については、次のドキュメントを参照してください。非同期で待機する。

基礎

Flutter アプリを作成するにはどうすればよいですか?

React Native を使用してアプリを作成するには、 あなたは走るでしょうcreate-react-native-appコマンドラインから。

$ create-react-native-app <projectname>

Flutter でアプリを作成するには、次のいずれかを実行します。

  • Flutter プラグインと Dart プラグインがインストールされた IDE を使用します。
  • 使用flutter createコマンドラインからコマンドを実行します。ことを確認してください。 Flutter SDK は PATH にあります。
$ flutter create <projectname>

詳細については、を参照してください。入門、 どれの ボタンクリックカウンターアプリの作成手順を説明します。 Flutter プロジェクトを作成すると、必要なすべてのファイルがビルドされます。 Android デバイスと iOS デバイスの両方でサンプル アプリを実行する必要があります。

アプリを実行するにはどうすればよいですか?

React Native では、次のように実行します。npm runまたyarn runプロジェクトから ディレクトリ。

Flutter アプリはいくつかの方法で実行できます。

  • Flutter プラグインと Dart プラグインを備えた IDE で「run」オプションを使用します。
  • 使用flutter runプロジェクトのルートディレクトリから。

アプリは接続されたデバイス、iOS シミュレーター上で実行されます。 またはAndroidエミュレータ。

詳細については、「 flutter」を参照してください。入門ドキュメンテーション。

ウィジェットをインポートするにはどうすればよいですか?

React Native では、必要な各コンポーネントをインポートする必要があります。

// React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

Flutter でマテリアル デザイン ライブラリのウィジェットを使用するには、 をインポートするmaterial.dartパッケージ。 iOS スタイルのウィジェットを使用するには、 クパチーノ図書館をインポートします。より基本的なウィジェット セットを使用するには、 ウィジェットライブラリをインポートします。 または、独自のウィジェット ライブラリを作成してインポートすることもできます。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:my_widgets/my_widgets.dart';

どのウィジェット パッケージをインポートしても、 Dart は、アプリで使用されているウィジェットのみを取り込みます。

詳細については、「Flutter ウィジェット カタログ

React Native の「Hello world!」に相当するものは何ですか? Flutterのアプリ?

React Native では、HelloWorldAppクラスが拡張するReact.Componentと ビューコンポーネントを返すことによって render メソッドを実装します。

// React Native
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

const App = () => {
  return (
    <View style={styles.container}>
      <Text>Hello world!</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
});

export default App;

Flutter では、まったく同じ「Hello world!」を作成できます。を使用するアプリCenterTextコア ウィジェット ライブラリからのウィジェット。 のCenterウィジェットはウィジェット ツリーのルートとなり、1 つの子を持ちます。 のTextウィジェット。

/// Flutter
import 'package:flutter/material.dart';

void main() {
  runApp(
    const Center(
      child: Text(
        'Hello, world!',
        textDirection: TextDirection.ltr,
      ),
    ),
  );
}

次の画像は、基本的な Flutter の Android および iOS UI を示しています。 "こんにちは世界!"アプリ。

Hello world app on Android
アンドロイド
Hello world app on iOS
iOS

最も基本的な Flutter アプリを見てきたので、次のセクションではその方法を示します。 Flutter の豊富なウィジェット ライブラリを活用して、モダンで洗練されたウィジェット ライブラリを作成します。 アプリ。

ウィジェットを使用し、それらをネストしてウィジェット ツリーを形成するにはどうすればよいですか?

Flutter では、ほとんどすべてがウィジェットです。

ウィジェットは、アプリのユーザー インターフェイスの基本的な構成要素です。 ウィジェットをウィジェット ツリーと呼ばれる階層に構成します。 各ウィジェットは親ウィジェット内にネストされます そしてその親からプロパティを継承します。 アプリケーション オブジェクト自体もウィジェットです。 個別の「アプリケーション」オブジェクトはありません。 代わりに、ルート ウィジェットがこの役割を果たします。

ウィジェットでは以下を定義できます。

  • ボタンやメニューなどの構造要素
  • フォントや配色などの文体要素
  • レイアウトの側面 - パディングや配置など

次の例は、「Hello world!」を示しています。のウィジェットを使用するアプリ マテリアルライブラリ。この例では、ウィジェット ツリーはMaterialAppルートウィジェット。

/// Flutter
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: const Center(
          child: Text('Hello world'),
        ),
      ),
    );
  }
}

次の画像は「Hello world!」を示しています。マテリアル デザイン ウィジェットから構築されています。 基本的な「Hello world!」よりも多くの機能を無料で利用できます。アプリ。

Hello world app on Android
アンドロイド
Hello world app on iOS
iOS

アプリを作成するときは、次の 2 種類のウィジェットを使用します。StatelessWidgetまたStatefulWidget。 あStatelessWidgetそれはまさにそのように聞こえます— 状態のないウィジェット。あStatelessWidget一度作成されると、 そしてその姿は決して変わりません。 あStatefulWidgetデータに基づいて状態を動的に変更する 受信したもの、またはユーザー入力。

ステートレスとステートフルの重要な違い ウィジェットはそれですStatefulWidgetは持っていますState物体 状態データを保存し、それを引き継ぐ ツリー全体が再構築されるため、失われることはありません。

シンプルまたは基本的なアプリでは、ウィジェットを簡単にネストできます。 しかし、コードベースが大きくなり、アプリが複雑になるにつれて、 深くネストされたウィジェットを分割する必要があります ウィジェットまたはより小さなクラスを返す関数。 個別の関数の作成 ウィジェットを使用すると、アプリ内でコンポーネントを再利用できます。

再利用可能なコンポーネントを作成するにはどうすればよいですか?

React Native では、クラスを定義して 再利用可能なコンポーネントを使用してくださいprops設定する方法 または、選択した要素のプロパティと値を返します。 以下の例では、CustomCardクラスが定義されている そして親クラス内で使用されます。

// React Native
const CustomCard = ({ index, onPress }) => {
  return (
    <View>
      <Text> Card {index} </Text>
      <Button
        title="Press"
        onPress={() => onPress(index)}
      />
    </View>
  );
};

// Usage
<CustomCard onPress={this.onPress} index={item.key} />

Flutter で、カスタム ウィジェットを作成するクラスを定義し、 ウィジェット。を返す関数を定義して呼び出すこともできます。 に示すように再利用可能なウィジェットbuild次の例の関数。

/// Flutter
class CustomCard extends StatelessWidget {
  const CustomCard({
    super.key,
    required this.index,
    required this.onPress,
  });

  final int index;
  final void Function() onPress;

  @override
  Widget build(BuildContext context) {
    return Card(
        child: Column(
      children: <Widget>[
        Text('Card $index'),
        TextButton(
          onPressed: onPress,
          child: const Text('Press'),
        ),
      ],
    ));
  }
}

class UseCard extends StatelessWidget {
  const UseCard({super.key, required this.index});

  final int index;

  @override
  Widget build(BuildContext context) {
    /// Usage
    return CustomCard(
      index: index,
      onPress: () {
        print('Card $index');
      },
    );
  }
}

前の例では、CustomCardクラスは Dart の中括弧構文を使用します{ }示す名前付きパラメータ。

これらのフィールドを必須にするには、次の中括弧を削除します。 コンストラクター、または追加requiredコンストラクターに。

次のスクリーンショットは、再利用可能なファイルの例を示しています。CustomCardクラス。

Custom cards on Android
アンドロイド
Custom cards on iOS
iOS

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

コードはどこから書き始めればよいでしょうか?

から始めてくださいlib/main.dartファイル。 Flutter アプリを作成すると自動生成されます。

// Dart
void main() {
  print('Hello, this is the main function.');
}

Flutter では、エントリ ポイント ファイルは次のとおりです。{project_name}/lib/main.dartそして実行 から始まりますmain関数。

Flutter アプリではファイルはどのように構造化されていますか?

新しい Flutter プロジェクトを作成すると、 次のディレクトリ構造を構築します。 後でカスタマイズすることもできますが、ここから始めます。

┬
└ project_name
  ┬
  ├ android      - Contains Android-specific files.
  ├ build        - Stores iOS and Android build files.
  ├ ios          - Contains iOS-specific files.
  ├ lib          - Contains externally accessible Dart source files.
    ┬
    └ src        - Contains additional source files.
    └ main.dart  - The Flutter entry point and the start of a new app.
                   This is generated automatically when you create a Flutter
                    project.
                   It's where you start writing your Dart code.
  ├ test         - Contains automated test files.
  └ pubspec.yaml - Contains the metadata for the Flutter app.
                   This is equivalent to the package.json file in React Native.

リソースや資産をどこに置き、どのように使用すればよいですか?

Flutter リソースまたはアセットは、バンドルされてデプロイされるファイルです アプリに組み込まれており、実行時にアクセスできます。 Flutter アプリには次のアセット タイプを含めることができます。

  • JSONファイルなどの静的データ
  • 設定ファイル
  • アイコンと画像 (JPEG、PNG、GIF、アニメーション GIF、WebP、アニメーション WebP、BMP、 および WBMP)

flutterはpubspec.yamlファイル、 プロジェクトのルートにあり、 アプリに必要なアセットを特定します。

flutter:
  assets:
    - assets/my_icon.png
    - assets/background.png

assetsサブセクションでは、アプリに含める必要があるファイルを指定します。 各アセットは明示的なパスによって識別されます に比べてpubspec.yamlファイル。アセットファイルが置かれている場所。 資産を宣言する順序は重要ではありません。 実際に使用されるディレクトリ (assetsこの場合)は関係ありません。 ただし、アセットは任意のアプリ ディレクトリに配置できますが、 に配置するベストプラクティスassetsディレクトリ。

ビルド中に、Flutter はアセットを特別なアーカイブに配置します と呼ばれるアセットバンドル、アプリが実行時に読み取るもの。 アセットのパスがアセットのセクションで指定されている場合pubspec.yaml、 ビルドプロセスはファイルを探します 隣接するサブディレクトリに同じ名前が付けられています。 これらのファイルはアセット バンドルにも含まれています 指定されたアセットとともに。 Flutter はアセット バリアントを使用します アプリに適切な解像度の画像を選択するとき。

React Native では、画像ファイルを配置して静的画像を追加します。 ソースコードディレクトリ内にあり、それを参照しています。

<Image source={require('./my-icon.png')} />
// OR
<Image
  source={{
    url: 'https://reactnative.dev/img/tiny_logo.png'
  }}
/>

Flutter でアプリに静的画像を追加します を使用してImage.assetウィジェットのビルドメソッドのコンストラクター。

Image.asset('assets/background.png');

詳細については、を参照してください。Flutter でのアセットと画像の追加

ネットワーク経由で画像をロードするにはどうすればよいですか?

React Native では、次のように指定します。uriの中にsourceの小道具Imageコンポーネントを提供し、 必要に応じてサイズを変更します。

Flutter では、Image.network含めるコンストラクター URLからの画像。

Image.network('https://docs.flutter.dev/assets/images/docs/owl.jpg');

パッケージとパッケージ プラグインをインストールするにはどうすればよいですか?

Flutter は、他の開発者が提供した共有パッケージの使用をサポートしています。 Flutter と Dart のエコシステム。これにより、何もせずにアプリを迅速に構築できます。 すべてをゼロから開発する必要があります。含まれるパッケージ プラットフォーム固有のコードは、パッケージ プラグインとして知られています。

React Native では、次のようにします。yarn add {package-name}またnpm install --save {package-name}パッケージをインストールするには コマンドラインから。

Flutter で、次の手順に従ってパッケージをインストールします。

  1. 追加するには、google_sign_inパッケージを依存関係として実行しますflutter pub add:
$ flutter pub add google_sign_in
  1. コマンドラインから次のようにパッケージをインストールします。flutter pub get。 IDE を使用している場合は、頻繁に実行されます。flutter pub getあなたにとって、あるいはそうかもしれない そうするように促します。
  2. 以下に示すように、パッケージをアプリコードにインポートします。
import 'package:flutter/material.dart';

詳細については、を参照してください。パッケージの使用パッケージとプラグインの開発

Flutter 開発者によって共有されている多くのパッケージは、 flutterパッケージのセクションパブ.dev。

flutterウィジェット

Flutter では、ビューを説明するウィジェットから UI を構築します。 現在の構成と状態を考慮すると、次のようになります。

多くの場合、ウィジェットは多数の小さな要素で構成されます。 強力な効果を生み出すためにネストされた単一目的のウィジェット。 たとえば、Containerウィジェットは次のもので構成されます レイアウト、ペイント、位置決め、サイズ変更を担当するいくつかのウィジェット。 具体的には、Containerウィジェットには以下が含まれますLimitedBoxConstrainedBoxAlignPaddingDecoratedBox、 とTransformウィジェット。 サブクラス化ではなくContainerカスタマイズされた効果を生成するには、次のことができます。 これらやその他のシンプルなウィジェットを新しくユニークな方法で作成します。

Centerウィジェットは、レイアウトを制御する方法のもう 1 つの例です。 ウィジェットを中央に配置するには、ウィジェットをCenterウィジェットを選択してレイアウトを使用する 配置、行、列、グリッド用のウィジェット。 これらのレイアウト ウィジェットには、独自の視覚的表現がありません。 代わりに、その唯一の目的は、別のシステムのある側面を制御することです。 ウィジェットのレイアウト。ウィジェットがなぜレンダリングされるのかを理解するには、 ある意味、隣接するウィジェットを検査すると役立つことがよくあります。

詳細については、「Flutterの技術概要

コア ウィジェットの詳細については、Widgetsパッケージ、 見るFlutter基本ウィジェット、 のFlutter ウィジェット カタログ、 または flutterウィジェットインデックス

ビュー

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

リアクトネイティブでは、ViewレイアウトをサポートするコンテナですFlexbox、 スタイル、タッチ操作、アクセシビリティ コントロール。

Flutter では、コア レイアウト ウィジェットをWidgets図書館などContainerColumnRow、 とCenter。 詳細については、「レイアウトウィジェットカタログ。

と同等のものは何ですかFlatListまたSectionList?

List垂直方向に配置されたコンポーネントのスクロール可能なリストです。

リアクトネイティブでは、FlatListまたSectionList単純なレンダリングに使用されるか、 セクション化されたリスト。

// React Native
<FlatList
  data={[ ... ]}
  renderItem={({ item }) => <Text>{item.key}</Text>}
/>

ListViewFlutter で最もよく使用されるスクロール ウィジェットです。 デフォルトのコンストラクターは、子の明示的なリストを受け取ります。ListView少数のウィジェットに最適です。 大規模なリストまたは無限のリストの場合は、次を使用します。ListView.builder、 要求に応じて子を構築し、構築するだけです 目に見えるあの子たち。

var data = [
  'Hello',
  'World',
];
return ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, index) {
    return Text(data[index]);
  },
);
Flat list on Android
アンドロイド
Flat list on iOS
iOS

無限スクロールリストを実装する方法については、公式を参照してください。infinite_listサンプル。

Canvas を使用して描画またはペイントするにはどうすればよいですか?

React Native にはキャンバス コンポーネントが存在しません したがって、サードパーティのライブラリは次のようになりますreact-native-canvas使用されています。

// React Native
const CanvasComp = () => {
  const handleCanvas = (canvas) => {
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'skyblue';
    ctx.beginPath();
    ctx.arc(75, 75, 50, 0, 2 * Math.PI);
    ctx.fillRect(150, 100, 300, 300);
    ctx.stroke();
  };

  return (
    <View>
      <Canvas ref={this.handleCanvas} />
    </View>
  );
}

Flutter では、CustomPaintとa31カフェ1-a32b-4beb-a1ea-cd6364b00629キャンバスに描画するクラス。

次の例は、ペイント フェーズ中にCustomPaintウィジェット。抽象クラスを実装します。CustomPainter、 そしてそれを渡しますCustomPaintの画家の所有物。CustomPaintサブクラスは以下を実装する必要がありますpaint()shouldRepaint()方法。

class MyCanvasPainter extends CustomPainter {
  const MyCanvasPainter();

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()..color = Colors.amber;
    canvas.drawCircle(const Offset(100, 200), 40, paint);
    final Paint paintRect = Paint()..color = Colors.lightBlue;
    final Rect rect = Rect.fromPoints(
      const Offset(150, 300),
      const Offset(300, 400),
    );
    canvas.drawRect(rect, paintRect);
  }

  @override
  bool shouldRepaint(MyCanvasPainter oldDelegate) => false;
}

class MyCanvasWidget extends StatelessWidget {
  const MyCanvasWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: CustomPaint(painter: MyCanvasPainter()),
    );
  }
}
Canvas on Android
アンドロイド
Canvas on iOS
iOS

レイアウト

ウィジェットを使用してレイアウト プロパティを定義するにはどうすればよいですか?

React Native では、ほとんどのレイアウトは props を使用して実行できます。 特定のコンポーネントに渡されます。 たとえば、次のように使用できます。style上のプロップView成分 フレックスボックスのプロパティを指定するため。 コンポーネントを列に配置するには、次のような prop を指定します。flexDirection: 'column'

// React Native
<View
  style={{
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'space-between',
    alignItems: 'center'
  }}
>

Flutter では、レイアウトは主にウィジェットによって定義されます レイアウトを提供するために特別に設計された、 コントロール ウィジェットとそのスタイル プロパティを組み合わせます。

たとえば、ColumnRowウィジェット 子の配列を取得して整列させます それぞれ縦と横。 あContainerウィジェットには次の組み合わせが必要です レイアウトとスタイルのプロパティ、およびCenterウィジェットはその子ウィジェットを中心に配置します。

@override
Widget build(BuildContext context) {
  return Center(
    child: Column(
      children: <Widget>[
        Container(
          color: Colors.red,
          width: 100,
          height: 100,
        ),
        Container(
          color: Colors.blue,
          width: 100,
          height: 100,
        ),
        Container(
          color: Colors.green,
          width: 100,
          height: 100,
        ),
      ],
    ),
  );

Flutter は、コア ウィジェット ライブラリでさまざまなレイアウト ウィジェットを提供します。 例えば、PaddingAlign、 とStack

完全なリストについては、を参照してください。レイアウトウィジェット

Layout on Android
アンドロイド
Layout on iOS
iOS

ウィジェットを階層化するにはどうすればよいですか?

React Native では、次を使用してコンポーネントを階層化できます。absoluteポジショニング。

flutterはStack子ウィジェットをレイヤーに配置するウィジェット。 ウィジェットは、ベース ウィジェットと完全にまたは部分的に重なることができます。

Stackウィジェットは、ボックスの端を基準にして子を配置します。 このクラスは、単に複数の子ウィジェットを重ねたい場合に便利です。

@override
Widget build(BuildContext context) {
  return Stack(
    alignment: const Alignment(0.6, 0.6),
    children: <Widget>[
      const CircleAvatar(
        backgroundImage: NetworkImage(
          'https://avatars3.githubusercontent.com/u/14101776?v=4',
        ),
      ),
      Container(
        color: Colors.black45,
        child: const Text('Flutter'),
      ),
    ],
  );

前の例では、Stackコンテナをオーバーレイするには (それを表示しますText半透明の黒い背景に) の上にCircleAvatar。 スタックは、配置プロパティを使用してテキストをオフセットします。 とAlignmentコーディネート。

Stack on Android
アンドロイド
Stack on iOS
iOS

詳細については、「Stackクラスのドキュメント。

スタイリング

コンポーネントのスタイルを設定するにはどうすればよいですか?

React Native では、インライン スタイルとstylesheets.createコンポーネントのスタイルを設定するために使用されます。

// React Native
<View style={styles.container}>
  <Text style={{ fontSize: 32, color: 'cyan', fontWeight: '600' }}>
    This is a sample text
  </Text>
</View>

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center'
  }
});

Flutter では、TextウィジェットはTextStyleクラス スタイルプロパティの場合。同じテキストを使用したい場合 複数の場所にスタイルを作成することができます。TextStyleクラスにして複数の用途に使用するTextウィジェット。

const TextStyle textStyle = TextStyle(
  color: Colors.cyan,
  fontSize: 32,
  fontWeight: FontWeight.w600,
);

return const Center(
  child: Column(
    children: <Widget>[
      Text('Sample text', style: textStyle),
      Padding(
        padding: EdgeInsets.all(20),
        child: Icon(
          Icons.lightbulb_outline,
          size: 48,
          color: Colors.redAccent,
        ),
      ),
    ],
  ),
);
Styling on Android
アンドロイド
Styling on iOS
iOS

使い方IconsColors?

React Native にはアイコンのサポートが含まれていません そのため、サードパーティのライブラリが使用されます。

Flutter では、マテリアル ライブラリをインポートすると、 の豊富なセットマテリアルアイコンと色。

return const Icon(Icons.lightbulb_outline, color: Colors.redAccent);

を使用するときは、Iconsクラス、 必ず設定してくださいuses-material-design: trueの プロジェクトのpubspec.yamlファイル。 これにより、MaterialIconsフォント、 アイコンを表示するツールはアプリに含まれています。 一般に、マテリアル ライブラリを使用する場合は、 この行を含める必要があります。

name: my_awesome_application
flutter:
  uses-material-design: true

flutterズクパチーノ (iOS スタイル)パッケージは高い 現在の iOS デザイン言語に忠実なウィジェット。 を使用するには、CupertinoIconsフォント、 依存関係を追加しますcupertino_iconsあなたのプロジェクトの中でpubspec.yamlファイル。

name: my_awesome_application
dependencies:
  cupertino_icons: ^0.1.0

コンポーネントの色とスタイルをグローバルにカスタマイズするには、 使用ThemeDataデフォルトの色を指定するには テーマのさまざまな側面について。 テーマのプロパティを設定しますMaterialAppThemeData物体。 のColorsクラスは色を提供します マテリアルデザインからカラーパレット。

次の例では、プライマリ スウォッチを次のように設定します。blueそしてテキストの選択はred

class SampleApp extends StatelessWidget {
  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(),
    );
  }
}

スタイルテーマを追加するにはどうすればよいですか?

React Native では、共通のテーマが定義されています。 コンポーネントをスタイルシートに追加し、コンポーネントで使用します。

Flutter では、ほぼすべてのものに対して均一なスタイルを作成します でスタイルを定義することで、ThemeDataクラスを作成し、それをテーマのプロパティに渡します。MaterialAppウィジェット。

@override
Widget build(BuildContext context) {
  return MaterialApp(
    theme: ThemeData(
      primaryColor: Colors.cyan,
      brightness: Brightness.dark,
    ),
    home: const StylingPage(),
  );
}

Themeを使用しなくても適用できますMaterialAppウィジェット。 のThemeウィジェットはThemeDataその中でdataパラメータ そして、ThemeDataすべての子ウィジェットに。

@override
Widget build(BuildContext context) {
  return Theme(
    data: ThemeData(
      primaryColor: Colors.cyan,
      brightness: brightness,
    ),
    child: Scaffold(
      backgroundColor: Theme.of(context).primaryColor,
      //...
    ),
  );
}

状態管理

状態は同期的に読み取ることができる情報です ウィジェットの構築時または情報 それはウィジェットの存続期間中に変更される可能性があります。 Flutter でアプリの状態を管理するには、 使うStatefulWidgetState オブジェクトとペアになります。

Flutter で状態を管理する方法の詳細については、 見る状態管理

ステートレスウィジェット

StatelessWidgetFlutter ではウィジェットです 状態を変更する必要はありません。 管理する内部状態はありません。

ステートレス ウィジェットは、ユーザー インターフェイスの一部である場合に便利です。 あなたが説明しているのは、 オブジェクト自体の構成情報と、BuildContextここではウィジェットがインフレートされています。

AboutDialogCircleAvatar、 とText例です サブクラス化するステートレス ウィジェットの数StatelessWidget

import 'package:flutter/material.dart';

void main() => runApp(
      const MyStatelessWidget(
        text: 'StatelessWidget Example to show immutable data',
      ),
    );

class MyStatelessWidget extends StatelessWidget {
  const MyStatelessWidget({
    super.key,
    required this.text,
  });

  final String text;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(
        text,
        textDirection: TextDirection.ltr,
      ),
    );
  }
}

前の例では、次のコンストラクターを使用しています。MyStatelessWidget合格するクラスtextとしてマークされています。final。 このクラスは拡張されますStatelessWidget— 不変のデータが含まれています。

build通常、ステートレス ウィジェットのメソッドが呼び出されます。 たった 3 つの状況の場合:

  • ウィジェットがツリーに挿入されるとき
  • ウィジェットの親がその構成を変更したとき
  • ときInheritedWidgetそれは依存する、変化する

ステートフルウィジェット

StatefulWidget状態を変更するウィジェットです。 使用setStateを管理する方法 状態が変化するStatefulWidget。 への電話setState() flutterに告げる 状態に何かが変化したという枠組み、 これにより、アプリはbuild()方法 アプリが変更を反映できるようにします。

ウィジェット作成時に同期的に読み込める情報です 構築され、ウィジェットの存続期間中に変更される可能性があります。 それを保証するのはウィジェット実装者の責任です。 状態が変化すると、状態オブジェクトに即座に通知されます。 使用StatefulWidgetウィジェットが動的に変更できる場合。 たとえば、フォームに入力するとウィジェットの状態が変化します。 またはスライダーを移動します。 または、時間の経過とともに変化する可能性があります。おそらく、データ フィードによって UI が更新されます。

CheckboxRadioSliderInkWellForm、 とTextFieldサブクラス化するステートフル ウィジェットの例です。StatefulWidget

次の例では、StatefulWidgetそれにはcreateState()方法。 このメソッドは、ウィジェットの状態を管理する状態オブジェクトを作成します。_MyStatefulWidgetState

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({
    super.key,
    required this.title,
  });

  final String title;

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

次の状態クラス、_MyStatefulWidgetState、 を実装しますbuild()ウィジェットのメソッド。 ユーザーが切り替えたときなど、状態が変化したとき ボタン、setState()新しいトグル値を使用して呼び出されます。 これにより、フレームワークは UI でこのウィジェットを再構築します。

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  bool showText = true;
  bool toggleState = true;
  Timer? t2;

  void toggleBlinkState() {
    setState(() {
      toggleState = !toggleState;
    });
    if (!toggleState) {
      t2 = Timer.periodic(const Duration(milliseconds: 1000), (t) {
        toggleShowText();
      });
    } else {
      t2?.cancel();
    }
  }

  void toggleShowText() {
    setState(() {
      showText = !showText;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          children: <Widget>[
            if (showText)
              const Text(
                'This execution will be done before you can blink.',
              ),
            Padding(
              padding: const EdgeInsets.only(top: 70),
              child: ElevatedButton(
                onPressed: toggleBlinkState,
                child: toggleState
                    ? const Text('Blink')
                    : const Text('Stop Blinking'),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

StatefulWidget と StatelessWidget のベスト プラクティスは何ですか?

ウィジェットを設計する際に考慮すべき点がいくつかあります。

  1. ウィジェットを次のようにするかどうかを決定します。 あるStatefulWidgetまたはStatelessWidget

Flutter では、ウィジェットはステートフルかステートレスのいずれかになります。 それらは状態の変化に依存します。

  • ウィジェットが変更された場合、ユーザーがウィジェットを操作するか、 データフィードが UI を中断すると、ステートフル
  • ウィジェットがfinalまたはimmutableの場合、それはステートレス
  1. どのオブジェクトがウィジェットの状態を管理するかを決定します (StatefulWidget)。

Flutter では、状態を管理する主な方法が 3 つあります。

  • ウィジェットは独自の状態を管理します
  • 親ウィジェットはウィジェットの状態を管理します
  • 組み合わせて使用​​するアプローチ

どのアプローチを使用するかを決定するときは、次の原則を考慮してください。

  • 問題の状態がユーザーデータの場合、 たとえば、チェックボックスのオンまたはオフのモード、 またはスライダーの位置の場合、状態を最も適切に管理できます。 親ウィジェットによって。
  • 問題の状態が美的である場合、たとえばアニメーションの場合、 その場合、ウィジェット自体が状態を最適に管理します。
  • 疑わしい場合は、親ウィジェットに子ウィジェットの状態を管理させてください。
  1. StatefulWidget と State をサブクラス化します。

MyStatefulWidgetクラスはそれ自体の状態を管理し、拡張しますStatefulWidget、それはオーバーライドしますcreateState()を作成する方法State物体、 そしてフレームワークは呼び出しますcreateState()ウィジェットを構築します。 この例では、createState()のインスタンスを作成します_MyStatefulWidgetState、 どれの 次のベスト プラクティスで実装されます。

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({
    super.key,
    required this.title,
  });

  final String title;
  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    //...
  }
}
  1. StatefulWidget をウィジェット ツリーに追加します。

カスタムを追加StatefulWidgetウィジェットツリーへ アプリのビルドメソッド内。

class MyStatelessWidget extends StatelessWidget {
  // This widget is the root of your application.
  const MyStatelessWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyStatefulWidget(title: 'State Change Demo'),
    );
  }
}
State change on Android
アンドロイド
State change on iOS
iOS

小道具

React Native では、ほとんどのコンポーネントをカスタマイズできます。 と呼ばれる、さまざまなパラメータまたはプロパティを使用して作成されます。props。 これらのパラメータは、次を使用して子コンポーネントで使用できます。this.props

// React Native
const CustomCard = ({ index, onPress }) => {
  return (
    <View>
      <Text> Card {index} </Text>
      <Button
        title='Press'
        onPress={() => onPress(index)}
      />
    </View>
  );
};

const App = () => {
  const onPress = (index) => {
    console.log('Card ', index);
  };

  return (
    <View>
      <FlatList
        data={[ /* ... */ ]}
        renderItem={({ item }) => (
          <CustomCard onPress={onPress} index={item.key} />
        )}
      />
    </View>
  );
};

Flutter では、マークされたローカル変数または関数を割り当てます。finalパラメーター化されたコンストラクターで受け取ったプロパティを使用します。

/// Flutter
class CustomCard extends StatelessWidget {
  const CustomCard({
    super.key,
    required this.index,
    required this.onPress,
  });

  final int index;
  final void Function() onPress;

  @override
  Widget build(BuildContext context) {
    return Card(
        child: Column(
      children: <Widget>[
        Text('Card $index'),
        TextButton(
          onPressed: onPress,
          child: const Text('Press'),
        ),
      ],
    ));
  }
}

class UseCard extends StatelessWidget {
  const UseCard({super.key, required this.index});

  final int index;

  @override
  Widget build(BuildContext context) {
    /// Usage
    return CustomCard(
      index: index,
      onPress: () {
        print('Card $index');
      },
    );
  }
}
Cards on Android
アンドロイド
Cards on iOS
iOS

ローカルストレージ

大量のデータを保存する必要がなく、保存する必要もない場合 構造、使用できますshared_preferencesこれにより、次のことが可能になります プリミティブ データの永続的なキーと値のペアの読み取りと書き込み 型: ブール値、float、int、long、string。

アプリに対してグローバルな永続的なキーと値のペアを保存するにはどうすればよいですか?

React Native では、setItemgetItem機能 のAsyncStorageデータを保存および取得するコンポーネント これは永続的であり、アプリに対してグローバルです。

// React Native
const [counter, setCounter] = useState(0)
...
await AsyncStorage.setItem( 'counterkey', json.stringify(++this.state.counter));
AsyncStorage.getItem('counterkey').then(value => {
  if (value != null) {
    setCounter(value);
  }
});

Flutter では、shared_preferencesプラグインから 永続的かつグローバルなキーと値のデータを保存および取得する アプリに。のshared_preferencesプラグインラップNSUserDefaultsiOS とSharedPreferencesアンドロイドでは、 単純なデータの永続的なストアを提供します。

追加するには、shared_preferencesパッケージを依存関係として実行しますflutter pub add:

$ flutter pub add shared_preferences
import 'package:shared_preferences/shared_preferences.dart';

永続データを実装するには、セッター メソッドを使用します。 によって提供されるSharedPreferencesクラス。 さまざまなプリミティブに対してセッターメソッドが利用可能 などのタイプsetIntsetBool、 とsetString。 データを読み取るには、提供されている適切なゲッター メソッドを使用します。 によってSharedPreferencesクラス。それぞれについて setter に対応する getter メソッドがあり、 例えば、getIntgetBool、 とgetString

Future<void> updateCounter() async {
  final prefs = await SharedPreferences.getInstance();
  int? counter = prefs.getInt('counter');
  if (counter is int) {
    await prefs.setInt('counter', ++counter);
  }
  setState(() {
    _counter = counter;
  });
}

ルーティング

ほとんどのアプリには、さまざまな画面を表示するための複数の画面が含まれています。 情報の種類。たとえば、次のような製品があるとします。 ユーザーが製品をタップできる画像を表示する画面 画像をクリックすると、新しい画面で製品に関する詳細情報が表示されます。

Android では、新しい画面は新しいアクティビティです。 iOS では、新しい画面は新しい ViewController です。 flutterでは、 画面は単なるウィジェットです。新しいページに移動するには Flutter の画面には、Navigator ウィジェットを使用します。

画面間を移動するにはどうすればよいですか?

React Native には、次の 3 つの主要なナビゲーターがあります。 StackNavigator、TabNavigator、および DrawerNavigator。 それぞれが画面を構成および定義する方法を提供します。

// React Native
const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: '#e91e63' } }
);
const SimpleApp = StackNavigator({
  Home: { screen: MyApp },
  stackScreen: { screen: StackScreen }
});
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));

Flutter には、画面間を移動するために使用される 2 つの主要なウィジェットがあります。

  • Routeアプリの画面またはページの抽象化です。
  • Navigatorルートを管理するウィジェットです。

Navigator子のセットを管理するウィジェットとして定義されます スタック規律を持つウィジェット。ナビゲーターはスタックを管理します のRouteオブジェクトを作成し、スタックを管理するためのメソッドを提供します。 好きNavigator.pushNavigator.pop。 ルートのリストは、MaterialAppウィジェット、 あるいは、ヒーロー アニメーションなどでその場で構築される場合もあります。 次の例では、名前付きルートを指定します。MaterialAppウィジェット。

class NavigationApp extends StatelessWidget {
  // This widget is the root of your application.
  const NavigationApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //...
      routes: <String, WidgetBuilder>{
        '/a': (context) => const UsualNavScreen(),
        '/b': (context) => const DrawerNavScreen(),
      },
      //...
    );
  }
}

名前付きルートに移動するには、Navigator.of()メソッドは、を指定するために使用されます。BuildContext(ウィジェット ツリー内のウィジェットの場所へのハンドル)。 ルートの名前はpushNamedに機能する 指定したルートに移動します。

Navigator.of(context).pushNamed('/a');

プッシュ方式を使用することもできますNavigatorどれの 与えられたものを追加しますRouteの歴史に 与えられたものを最もしっかりと囲むナビゲータBuildContext、 そしてそれに移行します。次の例では、 のMaterialPageRouteウィジェットはモーダル ルートです。 画面全体をプラットフォームに適応したものに置き換えます。 遷移。それにはWidgetBuilder必須パラメータとして。

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const UsualNavScreen(),
  ),
);

タブ ナビゲーションとドロワー ナビゲーションを使用するにはどうすればよいですか?

マテリアル デザイン アプリには、主に 2 つのオプションがあります Flutter ナビゲーションの場合: タブとドロワー。 タブや引き出しをサポートするスペースが不十分な場合 良い代替案を提供します。

タブナビゲーション

リアクトネイティブでは、createBottomTabNavigatorTabNavigationに慣れた タブの表示とタブ ナビゲーション用。

// React Native
import { createBottomTabNavigator } from 'react-navigation';

const MyApp = TabNavigator(
  { Home: { screen: HomeScreen }, Notifications: { screen: tabNavScreen } },
  { tabBarOptions: { activeTintColor: '#e91e63' } }
);

Flutter は、ドロワーと タブナビゲーション:

TabController
間でタブの選択を調整します。TabBarそしてTabBarView
TabBar
タブを横一列に表示します。
Tab
マテリアル デザインの TabBar タブを作成します。
TabBarView
現在選択されているタブに対応するウィジェットを表示します。
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  late TabController controller = TabController(length: 2, vsync: this);

  @override
  Widget build(BuildContext context) {
    return TabBar(
      controller: controller,
      tabs: const <Tab>[
        Tab(icon: Icon(Icons.person)),
        Tab(icon: Icon(Icons.email)),
      ],
    );
  }
}

TabControllerタブの選択を調整するために必要です の間TabBarそしてTabBarView。 のTabControllerコンストラクタlength引数は合計です タブの数。あTickerProviderトリガーするには必要です フレームが状態変更をトリガーするたびに通知が送信されます。 のTickerProvidervsync。を渡すvsync: thisに対する議論TabControllerコンストラクタ 新しいものを作成するたびに、TabController

TickerProvider実装されたインターフェースです 販売できるクラス別Tickerオブジェクト。 ティッカーは、通知が必要なオブジェクトであればいつでも使用できます。 フレーム トリガーですが、最も一般的には、AnimationControllerAnimationControllers 必要TickerProvider彼らのTicker。 StateからAnimationControllerを作成している場合、 その後、を使用できますTickerProviderStateMixinまたSingleTickerProviderStateMixin適切なクラスを取得するためのクラスTickerProvider

Scaffoldウィジェットは新しいものをラップしますTabBarウィジェットと 2 つのタブを作成します。のTabBarViewウィジェット として渡されますbodyのパラメータScaffoldウィジェット。 に対応するすべての画面TabBarウィジェットのタブは 子どもたちへTabBarViewウィジェットと同じものTabController

class _NavigationHomePageState extends State<NavigationHomePage>
    with SingleTickerProviderStateMixin {
  late TabController controller = TabController(length: 2, vsync: this);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        bottomNavigationBar: Material(
          color: Colors.blue,
          child: TabBar(
            tabs: const <Tab>[
              Tab(
                icon: Icon(Icons.person),
              ),
              Tab(
                icon: Icon(Icons.email),
              ),
            ],
            controller: controller,
          ),
        ),
        body: TabBarView(
          controller: controller,
          children: const <Widget>[HomeScreen(), TabScreen()],
        ));
  }
}

ドロワーナビゲーション

React Nativeでは、必要なreact-navigationパッケージをインポートしてから使用します。createDrawerNavigatorDrawerNavigation

// React Native
export default (MyApp1 = DrawerNavigator({
  Home: {
    screen: SimpleApp
  },
  Screen2: {
    screen: drawerScreen
  }
}));

Flutter では、Drawerウィジェットとの組み合わせScaffoldマテリアル デザイン ドロワーを使用してレイアウトを作成します。 を追加するにはDrawerアプリに追加するには、Scaffoldウィジェット。 のScaffoldウィジェットは一貫性を提供します に続くアプリの視覚的な構造マテリアルデザインガイドライン。もサポートします 特別なマテリアル デザイン コンポーネント、 そのようなDrawersAppBars、 とSnackBars

Drawerウィジェットはスライドするマテリアル デザイン パネルです 端から水平にScaffoldナビゲーションを表示するには アプリケーション内のリンク。あなたはできる を提供するElevatedButtonTextウィジェット、 または、その子として表示する項目のリストDrawerウィジェット。 次の例では、ListTileウィジェットはタップするとナビゲーションを提供します。

@override
Widget build(BuildContext context) {
  return Drawer(
    elevation: 20,
    child: ListTile(
      leading: const Icon(Icons.change_history),
      title: const Text('Screen2'),
      onTap: () {
        Navigator.of(context).pushNamed('/b');
      },
    ),
  );
}

Scaffoldウィジェットには、AppBar自動的に表示されるウィジェット を表示する適切な IconButton を表示します。Drawer引き出しがあるとき で利用可能Scaffold。のScaffold自動的に処理します エッジスワイプジェスチャを表示するには、Drawer

@override
Widget build(BuildContext context) {
  return Scaffold(
    drawer: Drawer(
      elevation: 20,
      child: ListTile(
        leading: const Icon(Icons.change_history),
        title: const Text('Screen2'),
        onTap: () {
          Navigator.of(context).pushNamed('/b');
        },
      ),
    ),
    appBar: AppBar(title: const Text('Home')),
    body: Container(),
  );
}
Navigation on Android
アンドロイド
Navigation on iOS
iOS

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

ジェスチャーを聞いて応答するには、 Flutter はタップ、ドラッグ、スケーリングをサポートしています。 Flutter のジェスチャ システムには 2 つの別々のレイヤーがあります。 最初の層には生のポインター イベントが含まれます。 ポインタの位置と動きを記述します。 (タッチ、マウス、スタイラスの動きなど) を画面全体に渡って実行します。 2 番目のレイヤーにはジェスチャが含まれます。 意味論的なアクションを記述する 1 つ以上のポインターの動きで構成されます。

クリックまたはプレスリスナーをウィジェットに追加するにはどうすればよいですか?

React Nativeでは、コンポーネントにリスナーが追加されます 使用してPanResponderまたはTouchableコンポーネント。

// React Native
<TouchableOpacity
  onPress={() => {
    console.log('Press');
  }}
  onLongPress={() => {
    console.log('Long Press');
  }}
>
  <Text>Tap or Long Press</Text>
</TouchableOpacity>

より複雑なジェスチャや複数のタッチを組み合わせる場合 たった一つのジェスチャー、PanResponder使用されている。

// React Native
const App = () => {
  const panResponderRef = useRef(null);

  useEffect(() => {
    panResponderRef.current = PanResponder.create({
      onMoveShouldSetPanResponder: (event, gestureState) =>
        !!getDirection(gestureState),
      onPanResponderMove: (event, gestureState) => true,
      onPanResponderRelease: (event, gestureState) => {
        const drag = getDirection(gestureState);
      },
      onPanResponderTerminationRequest: (event, gestureState) => true
    });
  }, []);

  return (
    <View style={styles.container} {...panResponderRef.current.panHandlers}>
      <View style={styles.center}>
        <Text>Swipe Horizontally or Vertically</Text>
      </View>
    </View>
  );
};

Flutter でクリック (またはプレス) リスナーをウィジェットに追加するには、 ボタンまたはタッチ可能なウィジェットを使用します。onPress: field。 または、ウィジェットをラップしてジェスチャ検出をウィジェットに追加します でGestureDetector

@override
Widget build(BuildContext context) {
  return GestureDetector(
    child: Scaffold(
      appBar: AppBar(title: const Text('Gestures')),
      body: const Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text('Tap, Long Press, Swipe Horizontally or Vertically'),
        ],
      )),
    ),
    onTap: () {
      print('Tapped');
    },
    onLongPress: () {
      print('Long Pressed');
    },
    onVerticalDragEnd: (value) {
      print('Swiped Vertically');
    },
    onHorizontalDragEnd: (value) {
      print('Swiped Horizontally');
    },
  );
}

リストなどの詳細については、 flutterGestureDetectorコールバック、 を参照してくださいGestureDetector クラス。

Gestures on Android
アンドロイド
Gestures on iOS
iOS

HTTPネットワークリクエストの実行

インターネットからデータを取得することは、ほとんどのアプリで一般的です。そして flutterでは、 のhttpパッケージは、インターネットからデータを取得する最も簡単な方法を提供します。

API 呼び出しからデータを取得するにはどうすればよいですか?

React Native はネットワーク用の Fetch API を提供します。フェッチ リクエストを作成します。 そして、データを取得するための応答を受信します。

// React Native
const [ipAddress, setIpAddress] = useState('')

const _getIPAddress = () => {
  fetch('https://httpbin.org/ip')
    .then(response => response.json())
    .then(responseJson => {
      setIpAddress(responseJson.origin);
    })
    .catch(error => {
      console.error(error);
    });
};

flutterはhttpパッケージ。

追加するには、httpパッケージを依存関係として実行しますflutter pub add:

$ flutter pub add http

flutterはdart:ioコア HTTP サポート クライアント。 HTTP クライアントを作成するには、インポートしますdart:io

import 'dart:io';

クライアントは次の HTTP 操作をサポートします。 取得、投稿、配置、および削除。

final url = Uri.parse('https://httpbin.org/ip');
final httpClient = HttpClient();

Future<void> getIPAddress() async {
  final request = await httpClient.getUrl(url);
  final response = await request.close();
  final responseBody = await response.transform(utf8.decoder).join();
  final String ip = jsonDecode(responseBody)['origin'];
  setState(() {
    _ipAddress = ip;
  });
}
API calls on Android
アンドロイド
API calls on iOS
iOS

フォーム入力

テキスト フィールドを使用すると、ユーザーはアプリにテキストを入力できるようになります。 フォーム、メッセージング アプリ、検索エクスペリエンスなどの構築に使用されます。 Flutter は 2 つのコア テキスト フィールド ウィジェットを提供します。TextFieldTextFormField

テキストフィールドウィジェットを使用するにはどうすればよいですか?

React Native では、テキストを入力するにはTextInputテキストを表示するコンポーネント 入力ボックスに入力し、コールバックを使用して値を変数に保存します。

// React Native
const [password, setPassword] = useState('')
...
<TextInput
  placeholder="Enter your Password"
  onChangeText={password => setPassword(password)}
/>
<Button title="Submit" onPress={this.validate} />

Flutter では、TextEditingControllerを管理するクラスTextFieldウィジェット。 テキストフィールドが変更されるたびに、 コントローラーはリスナーに通知します。

リスナーはテキストと選択プロパティを読み取って、 ユーザーがフィールドに入力した内容を学習します。 テキストにアクセスできますTextFieldによってtextコントローラーのプロパティ。

final TextEditingController _controller = TextEditingController();

@override
Widget build(BuildContext context) {
  return Column(children: [
    TextField(
      controller: _controller,
      decoration: const InputDecoration(
        hintText: 'Type something',
        labelText: 'Text Field',
      ),
    ),
    ElevatedButton(
      child: const Text('Submit'),
      onPressed: () {
        showDialog(
            context: context,
            builder: (context) {
              return AlertDialog(
                title: const Text('Alert'),
                content: Text('You typed ${_controller.text}'),
              );
            });
      },
    ),
  ]);
}

この例では、ユーザーが送信ボタンをクリックすると、警告ダイアログが表示されます。 テキストフィールドに入力されている現在のテキストを表示します。 これは、AlertDialog警告メッセージとそのテキストを表示するウィジェット のTextFieldによってアクセスされます料金5ba24-b834-44b9-b2ee-985254116592の財産TextEditingController

フォーム ウィジェットを使用するにはどうすればよいですか?

Flutter では、FormウィジェットどこTextFormFieldウィジェットと送信 ボタンは子として渡されます。 のTextFormFieldウィジェットには次のパラメータがありますonSavedコールバックを受け取って実行します フォームを保存したとき。あFormStateオブジェクトは保存、リセット、または検証に使用されます 各FormFieldそれはこの子孫ですForm。 を取得するには、FormState、使用できますForm.of()を祖先とするコンテキストを持つForm、 または渡すGlobalKeyFormコンストラクターと呼び出しGlobalKey.currentState()

@override
Widget build(BuildContext context) {
  return Form(
    key: formKey,
    child: Column(
      children: <Widget>[
        TextFormField(
          validator: (value) {
            if (value != null && value.contains('@')) {
              return null;
            }
            return 'Not a valid email.';
          },
          onSaved: (val) {
            _email = val;
          },
          decoration: const InputDecoration(
            hintText: 'Enter your email',
            labelText: 'Email',
          ),
        ),
        ElevatedButton(
          onPressed: _submit,
          child: const Text('Login'),
        ),
      ],
    ),
  );
}

次の例は、その方法を示していますForm.save()formKey(これはGlobalKey)、送信時にフォームを保存するために使用されます。

void _submit() {
  final form = formKey.currentState;
  if (form != null && form.validate()) {
    form.save();
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
            title: const Text('Alert'),
            content: Text('Email: $_email, password: $_password'));
      },
    );
  }
}
Input on Android
アンドロイド
Input on iOS
iOS

プラットフォーム固有のコード

クロスプラットフォーム アプリを構築するときは、できるだけ多くのコードを再利用したいと考えます。 プラットフォーム間で可能です。ただし、次のようなシナリオが発生する可能性があります。 OS によってコードが異なるのは当然です。 これには、特定のプラットフォームを宣言して個別に実装する必要があります。

React Native では、次の実装が使用されます。

// React Native
if (Platform.OS === 'ios') {
  return 'iOS';
} else if (Platform.OS === 'android') {
  return 'android';
} else {
  return 'not recognised';
}

Flutter では、次の実装を使用します。

final platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS) {
  return 'iOS';
}
if (platform == TargetPlatform.android) {
  return 'android';
}
if (platform == TargetPlatform.fuchsia) {
  return 'fuchsia';
}
return 'not recognized ';

デバッグ

Flutter でアプリをデバッグするにはどのようなツールを使用できますか?

使用開発ツールFlutter または Dart アプリをデバッグするためのスイート。

DevTools には、プロファイリング、ヒープの検査、 ウィジェット ツリーの検査、診断のログ記録、デバッグ、 実行されたコード行の監視、メモリ リークとメモリのデバッグ 断片化。詳細については、「開発ツールドキュメンテーション。

IDE を使用している場合は、 IDE のデバッガーを使用してアプリケーションをデバッグできます。

ホットリロードを実行するにはどうすればよいですか?

Flutter のステートフル ホット リロード機能は、迅速かつ簡単に実験するのに役立ちます。 UI を構築し、機能を追加し、バグを修正します。アプリを再コンパイルする代わりに 変更を加えるたびに、アプリを即座にホットリロードできます。 変更を反映してアプリが更新されます。 アプリの現在の状態は保持されます。

リアクトネイティブでは、 iOS シミュレーターのショートカットは ⌘R で、R を 2 回タップします。 Androidエミュレータ。

Flutter では、IntelliJ IDE または Android Studio を使用している場合、 「すべて保存」(⌘s/ctrl-s) を選択するか、 ツールバーのホットリロードボタン。もし、あんたが コマンドラインでアプリを実行しているflutter run、 タイプrターミナルウィンドウで。 次のように入力して完全な再起動を実行することもできます。Rの中に ターミナルウィンドウ。

アプリ内の開発者メニューにアクセスするにはどうすればよいですか?

React Native では、デバイスを振ることで開発者メニューにアクセスできます: ⌘D iOS シミュレータの場合は ⌘M、Android エミュレータの場合は。

Flutter では、IDE を使用している場合は、IDE ツールを使用できます。始めたら 使用しているアプリケーションflutter runと入力してメニューにアクセスすることもできますhターミナル ウィンドウで次のショートカットを入力するか、次のショートカットを入力します。

アクション ターミナルのショートカット デバッグ関数とプロパティ
アプリのウィジェット階層 w debugDumpApp()
アプリのレンダリングツリー t debugDumpRenderTree()
レイヤー L debugDumpLayerTree()
アクセシビリティ S(走査順序) または
U(ヒットテストの順序を逆にする)
debugDumpSemantics()
ウィジェットインスペクタを切り替えるには i ウィジェットアプリ。 showWidgetInspectorOverride
下書き線の表示を切り替えるには p デバッグペイントサイズ有効
さまざまなオペレーティング システムをシミュレートするには o デフォルトのターゲットプラットフォーム
パフォーマンスオーバーレイを表示するには P ウィジェットアプリ。 showパフォーマンスオーバーレイ
スクリーンショットを flutterに保存するには。 png s  
やめること q  

アニメーション

適切にデザインされたアニメーションにより UI が直感的に感じられ、 洗練されたアプリのルックアンドフィールに貢献し、 そしてユーザーエクスペリエンスが向上します。 Flutter のアニメーション サポートにより、それが簡単になります 単純なアニメーションと複雑なアニメーションを実装します。 Flutter SDK には多くのマテリアル デザイン ウィジェットが含まれています 標準のモーションエフェクトを含む これらの効果は簡単にカスタマイズできます アプリをパーソナライズします。

React Native では、アニメーション API を使用してアニメーションを作成します。

Flutter では、AnimationクラスとAnimationControllerクラス。Animationはそれを理解する抽象クラスです 現在の値とその状態 (完了または拒否)。 のAnimationControllerクラスでできること アニメーションを順方向または逆方向に再生します。 またはアニメーションを停止してアニメーションを設定します 特定の値に設定してモーションをカスタマイズします。

単純なフェードイン アニメーションを追加するにはどうすればよいですか?

以下の React Native の例では、アニメーション化されたコンポーネントが、FadeInViewアニメーション API を使用して作成されます。 不透明度の初期状態、最終状態、および 遷移が発生する期間が定義されます。 アニメーションコンポーネントは内部に追加されますAnimated成分、 不透明状態fadeAnimマッピングされています の不透明度にTextアニメーション化したいコンポーネント、 その後、start()アニメーションを開始するために呼び出されます。

// React Native
const FadeInView = ({ style, children }) => {
  const fadeAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 10000
    }).start();
  }, []);

  return (
    <Animated.View style={{ ...style, opacity: fadeAnim }}>
      {children}
    </Animated.View>
  );
};
    ...
<FadeInView>
  <Text> Fading in </Text>
</FadeInView>
    ...

Flutter で同じアニメーションを作成するには、AnimationControllerという名前のオブジェクトcontrollerそして期間を指定します。デフォルトでは、AnimationController0.0 から 1.0 の範囲の値を線形に生成します。 指定された期間中。アニメーション コントローラーは新しい値を生成します アプリを実行しているデバイスが新しいフレームを表示する準備ができたとき。 通常、このレートは 1 秒あたり約 60 値です。

を定義するとき、AnimationController、 を渡す必要がありますvsync物体。 の存在vsyncオフスクリーンを防ぐ アニメーションが不必要なリソースを消費しないようにします。 ステートフル オブジェクトをvsync追加することでTickerProviderStateMixinクラス定義に。 アンAnimationControllerTickerProvider が必要です。 これは、vsyncコンストラクターの引数。

Tweenの間の補間を記述します。 開始値と終了値、または入力からのマッピング レンジから出力レンジまで。を使用するにはTween物体 アニメーションを使用して、Tweenオブジェクトのanimate()メソッドを渡して、Animation変更するオブジェクト。

この例では、FadeTransitionウィジェットが使用されており、opacity財産は にマッピングされるanimation物体。

アニメーションを開始するには、次を使用しますcontroller.forward()。 他の操作も、 などのコントローラーfling()またrepeat()。 この例では、FlutterLogoウィジェットは内部で使用されますFadeTransitionウィジェット。

import 'package:flutter/material.dart';

void main() {
  runApp(const Center(child: LogoFade()));
}

class LogoFade extends StatefulWidget {
  const LogoFade({super.key});

  @override
  State<LogoFade> createState() => _LogoFadeState();
}

class _LogoFadeState extends State<LogoFade>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: const Duration(milliseconds: 3000),
      vsync: this,
    );
    final CurvedAnimation curve = CurvedAnimation(
      parent: controller,
      curve: Curves.easeIn,
    );
    animation = Tween(begin: 0.0, end: 1.0).animate(curve);
    controller.forward();
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: animation,
      child: const SizedBox(
        height: 300,
        width: 300,
        child: FlutterLogo(),
      ),
    );
  }
}
Flutter fade on Android
アンドロイド
Flutter fade on iOS
iOS

カードにスワイプ アニメーションを追加するにはどうすればよいですか?

React Native では、次のいずれかです。PanResponderまた スワイプ アニメーションにはサードパーティのライブラリが使用されます。

Flutter でスワイプ アニメーションを追加するには、Dismissibleウィジェットを作成し、子ウィジェットをネストします。

return Dismissible(
  key: Key(widget.key.toString()),
  onDismissed: (dismissDirection) {
    cards.removeLast();
  },
  child: Container(
      //...
      ),
);
Card swipe on Android
アンドロイド
Card swipe on iOS
iOS

React Native および Flutter ウィジェットと同等のコンポーネント

次の表は、一般的に使用される React Native の一覧です。 対応する Flutter ウィジェットにマップされたコンポーネント および共通のウィジェットのプロパティ。

反応ネイティブコンポーネント flutterウィジェット 説明
Button ElevatedButton ベーシックな上げボタン。
  onPressed [必須] ボタンがタップされたとき、またはその他の方法でアクティブ化されたときのコールバック。
  子供 ボタンのラベル。
     
Button TextButton ベーシックなフラットボタン。
  onPressed [必須] ボタンがタップされたとき、またはその他の方法でアクティブ化されたときのコールバック。
  子供 ボタンのラベル。
     
ScrollView ListView 直線的に配置されたウィジェットのスクロール可能なリスト。
  子供 ( <Widget> [ ]) 表示する子ウィジェットのリスト。
  コントローラ [ScrollController] スクロール可能なウィジェットを制御するために使用できるオブジェクト。
  項目範囲 [ double ] null 以外の場合、子がスクロール方向に指定された範囲を持つように強制されます。
  スクロール方向 [Axis] スクロール ビューがスクロールする軸。
     
FlatList ListView.builder オンデマンドで作成されるウィジェットの線形配列のコンストラクター。
  itemBuilder [必須] [IndexedWidgetBuilder] は、オンデマンドの子供たちを構築するのに役立ちます。このコールバックは、0 以上 itemCount 未満のインデックスを使用してのみ呼び出されます。
  項目数 [ int ] の能力を向上させます。ListView最大スクロール範囲を推定します。
     
Image Image 画像を表示するウィジェットです。
  画像[必須] 表示する画像。
  画像。資産 画像を指定するさまざまな方法のために、いくつかのコンストラクターが提供されています。
  幅、高さ、色、配置 画像のスタイルとレイアウト。
  フィット レイアウト時に割り当てられたスペースに画像を埋め込みます。
     
Modal ModalRoute 以前のルートとの相互作用をブロックするルート。
  アニメーション ルートのトランジションと前のルートの前方トランジションを駆動するアニメーション。
     
ActivityIndicator CircularProgressIndicator 円に沿って進行状況を表示するウィジェット。
  ストローク幅 円を描くために使用される線の幅。
  背景色 進行状況インジケーターの背景色。現在のテーマはThemeData.backgroundColorデフォルトでは。
     
ActivityIndicator LinearProgressIndicator 線に沿って進行状況を表示するウィジェット。
  価値 この進行状況インジケーターの値。
     
RefreshControl RefreshIndicator マテリアルの「スワイプして更新」イディオムをサポートするウィジェット。
  進行状況インジケーターの前景色。
  更新時 ユーザーがアプリを更新することを示すために更新インジケーターを十分にドラッグしたときに呼び出される関数。
     
View Container 子ウィジェットを囲むウィジェット。
     
View Column 子を垂直配列で表示するウィジェット。
     
View Row 子を水平配列で表示するウィジェット。
     
View Center 子を自身の中心に配置するウィジェット。
     
View Padding 指定されたパディングによって子を挿入するウィジェット。
  パディング [必須] [ EdgeInsets ] 子を挿入するスペースの量。
     
TouchableOpacity GestureDetector ジェスチャーを検出するウィジェット。
  オンタップ タップが発生したときのコールバック。
  ダブルタップ時 同じ場所でタップが 2 回続けて発生した場合のコールバック。
     
TextInput TextInput システムのテキスト入力コントロールへのインターフェイス。
  コントローラ [TextEditingController] テキストにアクセスして変更するために使用されます。
     
Text Text 単一のスタイルでテキスト文字列を表示するテキスト ウィジェット。
  データ [ String ] 表示するテキスト。
  テキスト方向 [TextAlign] テキストが流れる方向。
     
Switch Switch マテリアルデザインのスイッチ。
  値[必須] [ boolean ] このスイッチがオンかオフか。
  onChanged [必須] [ callback ] ユーザーがスイッチをオンまたはオフに切り替えるときに呼び出されます。
     
Slider Slider 値の範囲から選択するために使用されます。
  値[必須] [ double ] スライダーの現在の値。
  onChanged [必須] ユーザーがスライダーの新しい値を選択すると呼び出されます。