Flutter-クイックガイド

一般に、モバイルアプリケーションの開発は、複雑で困難な作業です。モバイルアプリケーションを開発するために利用できる多くのフレームワークがあります。 AndroidはJava言語に基づくネイティブフレームワークを提供し、iOSはObjective-C / Swift言語に基づくネイティブフレームワークを提供します。

ただし、両方のOSをサポートするアプリケーションを開発するには、2つの異なるフレームワークを使用して2つの異なる言語でコーディングする必要があります。この複雑さを克服するために、両方のOSをサポートするモバイルフレームワークが存在します。これらのフレームワークは、単純なHTMLベースのハイブリッドモバイルアプリケーションフレームワーク(ユーザーインターフェイスにHTMLを使用し、アプリケーションロジックにJavaScriptを使用)から複雑な言語固有のフレームワーク(コードをネイティブコードに変換するという手間のかかる作業)にまで及びます。これらのフレームワークには、その単純さや複雑さに関係なく、常に多くの欠点があります。主な欠点の1つは、パフォーマンスが遅いことです。

このシナリオでは、Dart言語に基づくシンプルで高性能なフレームワークであるFlutterは、ネイティブフレームワークではなく、オペレーティングシステムのキャンバスにUIを直接レンダリングすることで、高性能を提供します。

Flutterは、最新のアプリケーションを作成するためのすぐに使用できるウィジェット(UI)も多数提供しています。これらのウィジェットはモバイル環境向けに最適化されており、ウィジェットを使用したアプリケーションの設計はHTMLの設計と同じくらい簡単です。

具体的には、Flutterアプリケーション自体がウィジェットです。Flutterウィジェットはアニメーションとジェスチャーもサポートしています。アプリケーションロジックは、リアクティブプログラミングに基づいています。ウィジェットはオプションで状態を持つことができます。ウィジェットの状態を変更することにより、Flutterはウィジェットの状態(古いものと新しいもの)を自動的に(リアクティブプログラミング)比較し、ウィジェット全体を再レンダリングするのではなく、必要な変更のみでウィジェットをレンダリングします。

完全なアーキテクチャについては、次の章で説明します。

Flutterの特徴

Flutterフレームワークは開発者に次の機能を提供します-

  • 現代的で反応的なフレームワーク。

  • Dartプログラミング言語を使用しており、習得が非常に簡単です。

  • 迅速な開発。

  • 美しく流動的なユーザーインターフェイス。

  • 巨大なウィジェットカタログ。

  • 複数のプラットフォームで同じUIを実行します。

  • 高性能アプリケーション。

Flutterの利点

Flutterには、高性能で卓越したモバイルアプリケーション向けの美しくカスタマイズ可能なウィジェットが付属しています。それはすべてのカスタムニーズと要件を満たします。これらに加えて、Flutterには以下に述べるようにさらに多くの利点があります-

  • Dartには、アプリケーションの機能を拡張できるソフトウェアパッケージの大規模なリポジトリがあります。

  • 開発者は、両方のアプリケーション(AndroidプラットフォームとiOSプラットフォームの両方)に対して単一のコードベースを作成する必要があります。Flutterは、将来的に他のプラットフォームにも拡張される可能性があります。

  • Flutterはより少ないテストを必要とします。コードベースが1つであるため、両方のプラットフォームに対して自動テストを1回作成すれば十分です。

  • Flutterのシンプルさは、迅速な開発に適しています。そのカスタマイズ機能と拡張性により、さらに強力になります。

  • Flutterを使用すると、開発者はウィジェットとそのレイアウトを完全に制御できます。

  • Flutterは、驚くべきホットリロードを備えた優れた開発ツールを提供します。

Flutterのデメリット

その多くの利点にもかかわらず、フラッターには次の欠点があります-

  • Dart言語でコーディングされているため、開発者は新しい言語を学ぶ必要があります(習得は簡単ですが)。

  • 最新のフレームワークは、ロジックとUIを可能な限り分離しようとしますが、Flutterでは、ユーザーインターフェイスとロジックが混在しています。スマートコーディングと高レベルモジュールを使用してユーザーインターフェイスとロジックを分離することで、これを克服できます。

  • Flutterは、モバイルアプリケーションを作成するためのさらに別のフレームワークです。開発者は、人口の多いセグメントで適切な開発ツールを選択するのに苦労しています。

この章では、ローカルコンピューターへのFlutterのインストールについて詳しく説明します。

Windowsでのインストール

このセクションでは、FlutterSDKをWindowsシステムにインストールする方法とその要件を見てみましょう。

Step 1 − URLに移動し、https://flutter.dev/docs/get-started/install/windows最新のFlutterSDKをダウンロードします。2019年4月現在、バージョンは1.2.1で、ファイルはflutter_windows_v1.2.1-stable.zipです。

Step 2 − zipアーカイブをフォルダー(C:\ flutter \など)に解凍します。

Step 3 −システムパスを更新して、フラッタービンディレクトリを含めます。

Step 4 − Flutterは、フラッター開発のすべての要件が満たされていることを確認するためのツール、フラッタードクターを提供します。

flutter doctor

Step 5 −上記のコマンドを実行すると、システムが分析され、以下に示すようにレポートが表示されます。

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version
10.0.17134.706], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version
28.0.3)
[√] Android Studio (version 3.2)
[√] VS Code, 64-bit edition (version 1.29.1)
[!] Connected device
! No devices available
! Doctor found issues in 1 category.

レポートには、すべての開発ツールが利用可能であるが、デバイスが接続されていないことが記載されています。これは、AndroidデバイスをUSB経由で接続するか、Androidエミュレーターを起動することで修正できます。

Step 6 − Flutter Doctorから報告された場合は、最新のAndroidSDKをインストールします

Step 7 −フラッタードクターから報告された場合は、最新のAndroidStudioをインストールします

Step 8 − Androidエミュレーターを起動するか、実際のAndroidデバイスをシステムに接続します。

Step 9− AndroidStudio用のFlutterandDartプラグインをインストールします。新しいFlutterアプリケーションを作成するためのスタートアップテンプレート、AndroidStudio自体でFlutterアプリケーションを実行およびデバッグするためのオプションなどを提供します。

  • AndroidStudioを開きます。

  • 「ファイル」→「設定」→「プラグイン」をクリックします。

  • Flutterプラグインを選択し、[インストール]をクリックします。

  • Dartプラグインをインストールするように求められたら、[はい]をクリックします。

  • AndroidStudioを再起動します。

MacOSでのインストール

MacOSにFlutterをインストールするには、次の手順に従う必要があります-

Step 1 − URLに移動し、https://flutter.dev/docs/get-started/install/macos最新のFlutterSDKをダウンロードします。2019年4月の時点で、バージョンは1.2.1で、ファイルはflutter_macos_v1.2.1-stable.zipです。

Step 2 −zipアーカイブを/ path / to / flutterなどのフォルダーに解凍します

Step 3 −システムパスを更新して、フラッタービンディレクトリ(〜/ .bashrcファイル内)を含めます。

> export PATH = "$PATH:/path/to/flutter/bin"

Step 4 −以下のコマンドを使用して、現在のセッションで更新されたパスを有効にしてから、それも確認します。

source ~/.bashrc
source $HOME/.bash_profile
echo $PATH

Flutterは、フラッター開発のすべての要件が満たされていることを確認するためのツール、フラッタードクターを提供します。これは、Windowsの対応物に似ています。

Step 5 −フラッタードクターから報告された場合は、最新のXCodeをインストールします

Step 6 − Flutter Doctorから報告された場合は、最新のAndroidSDKをインストールします

Step 7 −フラッタードクターから報告された場合は、最新のAndroidStudioをインストールします

Step 8 − Androidエミュレーターを起動するか、実際のAndroidデバイスをシステムに接続してAndroidアプリケーションを開発します。

Step 9 − iOSシミュレーターを開くか、実際のiPhoneデバイスをシステムに接続してiOSアプリケーションを開発します。

Step 10− AndroidStudio用のFlutterandDartプラグインをインストールします。新しいFlutterアプリケーションを作成するためのスタートアップテンプレート、AndroidStudio自体でFlutterアプリケーションを実行およびデバッグするためのオプションなどを提供します。

  • AndroidStudioを開く

  • クリック Preferences → Plugins

  • Flutterプラグインを選択し、[インストール]をクリックします

  • Dartプラグインをインストールするように求められたら、[はい]をクリックします。

  • AndroidStudioを再起動します。

この章では、Android Studioでフラッターアプリケーションを作成するための基本を理解するために、簡単なフラッターアプリケーションを作成しましょう。

Step 1 − AndroidStudioを開く

Step 2−フラッタープロジェクトを作成します。これについては、File → New → New Flutter Project

Step 3−フラッターアプリケーションを選択します。このために、Flutter Application をクリックします Next

Step 4 −以下のようにアプリケーションを構成し、をクリックします Next

  • プロジェクト名: hello_app

  • Flutter SDKパス: <path_to_flutter_sdk>

  • プロジェクトの場所: <path_to_project_folder>

  • 説明: Flutter based hello world application

Step 5 −プロジェクトを構成します。

会社のドメインを次のように設定します flutterapp.tutorialspoint.com をクリックします Finish

Step 6 −会社のドメインを入力します。

Android Studioは、最小限の機能で完全に機能するフラッターアプリケーションを作成します。アプリケーションの構造を確認してから、コードを変更してタスクを実行しましょう。

アプリケーションの構造と目的は次のとおりです。

ここでは、アプリケーションの構造のさまざまなコンポーネントについて説明します。

  • android −Androidアプリケーションを作成するための自動生成されたソースコード

  • ios −iOSアプリケーションを作成するための自動生成されたソースコード

  • lib −フラッターフレームワークを使用して記述されたDartコードを含むメインフォルダー

  • ib/main.dart −Flutterアプリケーションのエントリポイント

  • test −フラッターアプリケーションをテストするためのDartコードを含むフォルダー

  • test/widget_test.dart −サンプルコード

  • .gitignore −Gitバージョン管理ファイル

  • .metadata −フラッターツールによって自動生成

  • .packages −フラッターパッケージを追跡するために自動生成

  • .iml −AndroidStudioで使用されるプロジェクトファイル

  • pubspec.yaml −使用者 Pub、Flutterパッケージマネージャー

  • pubspec.lock −Flutterパッケージマネージャーによって自動生成されます。 Pub

  • README.md −マークダウン形式で記述されたプロジェクト記述ファイル

Step 7lib / main.dartファイルのdartコードを以下のコードに置き換えます

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application',
         theme: ThemeData(
            primarySwatch: Colors.blue,
         ),
         home: MyHomePage(title: 'Home page'),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;

   @override
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title),
         ),
         body: Center(
            child:
            Text(
               'Hello World',
            )
         ),
      );
   }
}

ダーツコードを1行ずつ理解しましょう。

  • Line 1−フラッターパッケージ、マテリアルをインポートします。マテリアルは、Androidで指定されたマテリアルデザインガイドラインに従ってユーザーインターフェースを作成するためのフラッターパッケージです。

  • Line 3−これはFlutterアプリケーションのエントリポイントです。runApp関数を呼び出し、MyAppクラスのオブジェクトに渡しますrunApp関数の目的は、指定されたウィジェットを画面にアタッチすることです。

  • Line 5-17−ウィジェットはフラッターフレームワークでUIを作成するために使用されます。StatelessWidgetはウィジェットであり、ウィジェットの状態を維持しません。MyAppStatelessWidgetを拡張し、そのビルドメソッドをオーバーライドします。buildメソッドの目的は、アプリケーションのUIの一部を作成することです。ここで、buildメソッドは、ウィジェットであるMaterialAppを使用して、アプリケーションのルートレベルのUIを作成します。タイトル、テーマホームの3つのプロパティがあります。

    • titleはアプリケーションのタイトルです

    • テーマはウィジェットのテーマです。ここでは、ThemeDataクラスとそのプロパティprimarySwatchを使用して、アプリケーションの全体的な色としてを設定します。

    • ホームはアプリケーションの内部UIであり、別のウィジェットを設定します。 MyHomePage

  • Line 19 - 38MyHomePageは、ScaffoldWidgetを返すことを除いてMyAppと同じです。Scaffoldは、UI準拠のマテリアルデザインを作成するために使用されるMaterialAppウィジェットの隣にあるトップレベルのウィジェットです。これには、アプリケーションのヘッダーを表示するappBarと、アプリケーションの実際のコンテンツを表示するbodyの2つの重要なプロパティがあります。AppBarは、アプリケーションのヘッダーをレンダリングするためのもう1つのウィジェットであり、appBarプロパティで使用してます。では、本体のプロパティは、我々が使用しているセンターのそれを子ウィジェットを中心ウィジェットを、。テキストは、テキストを表示するための最後の最も内側のウィジェットであり、画面の中央に表示されます。

Step 8 −次に、を使用してアプリケーションを実行します。 Run → Run main.dart

Step 9 −最後に、アプリケーションの出力は次のとおりです。

この章では、Flutterフレームワークのアーキテクチャについて説明します。

ウィジェット

Flutterフレームワークのコアコンセプトは In Flutter, Everything is a widget。ウィジェットは基本的に、アプリケーションのユーザーインターフェイスを作成するために使用されるユーザーインターフェイスコンポーネントです。

フラッター、アプリケーションはウィジェットそのものです。アプリケーションはトップレベルのウィジェットであり、そのUIは1つ以上の子(ウィジェット)を使用してビルドされます。この子ウィジェットも子ウィジェットを使用してビルドされます。このcomposability この機能は、複雑なユーザーインターフェイスを作成するのに役立ちます。

たとえば、hello worldアプリケーション(前の章で作成)のウィジェット階層は、次の図で指定されているとおりです。

ここで注目すべき点は次のとおりです。

  • MyAppはユーザーが作成したウィジェットであり、FlutterネイティブウィジェットであるMaterialAppを使用してビルドされます。

  • MaterialAppには、ホームページのユーザーインターフェイスを指定するhomeプロパティがあります。これも、ユーザーが作成したウィジェットMyHomePageです。

  • MyHomePageは、別のフラッターネイティブウィジェットであるScaffoldを使用してビルドされています

  • Scaffoldには、bodyappBarの2つのプロパティがあります。

  • bodyはメインユーザーインターフェイスを指定するために使用され、appBarはヘッダーユーザーインターフェイスを指定するために使用されます

  • ヘッダーUIはフラッターネイティブウィジェットを使用してビルドされ、AppBarボディUIセンターウィジェットを使用してビルドされます。

  • センター性質、持っているウィジェットの子を実際のコンテンツを参照し、それが使用してビルドされ、テキストウィジェットを

ジェスチャー

Flutterウィジェットは、特別なウィジェットであるGestureDetectorを介した対話をサポートします。GestureDetectorは、子ウィジェットのタップ、ドラッグなどのユーザーインタラクションをキャプチャする機能を備えた非表示のウィジェットです。Flutterの多くのネイティブウィジェットは、GestureDetectorを使用したインタラクションをサポートしています。GestureDetectorウィジェットで構成することにより、既存のウィジェットにインタラクティブ機能を組み込むこともできます。次の章では、ジェスチャーを個別に学習します。

国家の概念

Flutterウィジェットは、特別なウィジェットStatefulWidgetを提供することにより、状態のメンテナンスをサポートします。ウィジェットは、状態のメンテナンスをサポートするためにStatefulWidgetウィジェットから派生する必要があり、他のすべてのウィジェットはStatefulWidgetから派生する必要があります。フラッターウィジェットはreactiveネイティブで。これはreactjsに似ており、StatefulWidgetは内部状態が変更されるたびに自動再レンダリングされます。再レンダリングは、新旧のウィジェットUIの違いを見つけ、必要な変更のみをレンダリングすることで最適化されます

レイヤー

Flutterフレームワークの最も重要な概念は、フレームワークが複雑さの観点から複数のカテゴリにグループ化され、複雑さが減少するレイヤーに明確に配置されることです。レイヤーは、そのすぐ次のレベルのレイヤーを使用して構築されます。最上位のレイヤーは、AndroidiOSに固有のウィジェットです。次のレイヤーには、すべてのフラッターネイティブウィジェットがあります。次のレイヤーはレンダリングレイヤーです。これは低レベルのレンダラーコンポーネントであり、フラッターアプリのすべてをレンダリングします。レイヤーはコアプラットフォーム固有のコードになります

Flutterのレイヤーの一般的な概要は、次の図で指定されています-

以下のポイントは、Flutterのアーキテクチャをまとめたものです。

  • Flutterでは、すべてがウィジェットであり、複雑なウィジェットは既存のウィジェットで構成されています。

  • GestureDetectorウィジェットを使用して、必要に応じてインタラクティブ機能を組み込むことができます。

  • ウィジェットの状態は、StatefulWidgetウィジェットを使用して必要なときにいつでも維持できます。

  • Flutterはレイヤードデザインを提供するため、タスクの複雑さに応じて任意のレイヤーをプログラムできます。

これらすべての概念については、次の章で詳しく説明します。

Dartは、オープンソースの汎用プログラミング言語です。もともとはGoogleによって開発されました。Dartは、Cスタイルの構文を持つオブジェクト指向言語です。Dartが配列をサポートしていない他のプログラミング言語とは異なり、インターフェイスやクラスなどのプログラミング概念をサポートしています。Dartコレクションを使用して、配列、ジェネリック、オプションの型指定などのデータ構造を複製できます。

次のコードは、単純なDartプログラムを示しています-

void main() {
   print("Dart language is easy to learn");
}

変数とデータ型

変数は保存場所と呼ばれ、データ型は単に変数と関数に関連付けられたデータの種類とサイズを指します。

Dartはvarキーワードを使用して変数を宣言します。varの構文は次のように定義されています。

var name = 'Dart';

最終のconstキーワードが宣言定数に使用されています。それらは以下のように定義されます-

void main() {
   final a = 12;
   const pi = 3.14;
   print(a);
   print(pi);
}

Dart言語は次のデータ型をサポートしています-

  • Numbers −数値リテラル(整数および倍精度)を表すために使用されます。

  • Strings−文字のシーケンスを表します。文字列値は一重引用符または二重引用符で指定されます。

  • Booleans− Dartはboolキーワードを使用して、ブール値(trueおよびfalse)を表します。

  • Lists and Maps−オブジェクトのコレクションを表すために使用されます。単純なリストは次のように定義できます-。

void main() {
   var list = [1,2,3,4,5];
   print(list);
}

上記のリストは[1,2,3,4,5]リストを生成します。

マップはここに示すように定義できます-

void main() {
   var mapping = {'id': 1,'name':'Dart'};
   print(mapping);
}
  • Dynamic−変数タイプが定義されていない場合、そのデフォルトタイプは動的です。次の例は、動的型変数-を示しています。

void main() {
   dynamic name = "Dart";
   print(name);
}

意思決定とループ

意思決定ブロックは、命令が実行される前に条件を評価します。Dartは、If、If..else、およびswitchステートメントをサポートしています。

ループは、特定の条件が満たされるまでコードのブロックを繰り返すために使用されます。Dartは、for..in、while、do..whileループをサポートしています。

制御ステートメントとループの使用法についての簡単な例を理解しましょう-

void main() {
   for( var i = 1 ; i <= 10; i++ ) {
      if(i%2==0) {
         print(i);
      }
   }
}

上記のコードは、1から10までの偶数を出力します。

関数

関数は、特定のタスクを一緒に実行するステートメントのグループです。ここに示すように、Dartの単純な関数を調べてみましょう-

void main() {
   add(3,4);
}
void add(int a,int b) {
   int c;
   c = a+b;
   print(c);
}

上記の関数は2つの値を加算し、出力として7を生成します。

オブジェクト指向プログラミング

Dartはオブジェクト指向言語です。クラス、インターフェースなどのオブジェクト指向プログラミング機能をサポートします。

クラスは、オブジェクトを作成するための青写真です。クラス定義には次のものが含まれます-

  • Fields
  • ゲッターとセッター
  • Constructors
  • Functions

ここで、上記の定義を使用して単純なクラスを作成しましょう-

class Employee {
   String name;
   
   //getter method
   String get emp_name {
      return name;
   }
   //setter method
   void set emp_name(String name) {
      this.name = name;
   }
   //function definition
   void result() {
      print(name);
   }
}
void main() {
   //object creation
   Employee emp = new Employee();
   emp.name = "employee1";
   emp.result(); //function call
}

前の章で学んだように、ウィジェットはFlutterフレームワークのすべてです。前の章で、新しいウィジェットを作成する方法をすでに学びました。

この章では、ウィジェットの作成の背後にある実際の概念と、Flutterフレームワークで使用できるさまざまなタイプのウィジェットについて理解しましょう。

私たちはチェックしてみましょうのHello WorldアプリケーションのMyHomePageウィジェットを。この目的のためのコードは以下のとおりです-

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar(title: Text(this.title), ), 
         body: Center(child: Text( 'Hello World',)),
      );
   }
}

ここでは、StatelessWidgetを拡張して新しいウィジェットを作成しました。

StatelessWidgetは、派生クラスに実装するために1つのメソッドビルドのみを必要とすることに注意してください。ビルド方法はを通じてウィジェットを構築するために必要なコンテキスト環境取得BuildContextのパラメータを、それが構築するウィジェットを返します。

コードでは、コンストラクター引数の1つとしてtitleを使用し、別の引数としてKeyも使用しています。タイトルがタイトルを表示するために使用され、キーがビルド環境にウィジェットを識別するために使用されます。

ここで、buildメソッドはScaffoldbuildメソッドを呼び出し、ScaffoldAppBarCenterのbuildメソッドを呼び出してユーザーインターフェイスを構築します。

最後に、CenterビルドメソッドはTextビルドメソッドを呼び出します。

理解を深めるために、同じものの視覚的表現を以下に示します。

ウィジェットビルドの視覚化

フラッタ下記のように、ウィジェットは、それらの特徴に基づいて複数のカテゴリに分類することができます-

  • プラットフォーム固有のウィジェット
  • レイアウトウィジェット
  • 状態メンテナンスウィジェット
  • プラットフォームに依存しない/基本的なウィジェット

ここで、それぞれについて詳しく説明します。

プラットフォーム固有のウィジェット

Flutterには、特定のプラットフォーム(AndroidまたはiOS)に固有のウィジェットがあります。

Android固有のウィジェットは、AndroidOSによるマテリアルデザインガイドラインに従って設計されています。Android固有のウィジェットは、マテリアルウィジェットと呼ばれます

iOS固有のウィジェットは、Appleのヒューマンインターフェイスガイドラインに従って設計されており、Cupertinoウィジェットと呼ばれます。

最もよく使用されるマテリアルウィジェットのいくつかは次のとおりです-

  • Scaffold
  • AppBar
  • BottomNavigationBar
  • TabBar
  • TabBarView
  • ListTile
  • RaisedButton
  • FloatingActionButton
  • FlatButton
  • IconButton
  • DropdownButton
  • PopupMenuButton
  • ButtonBar
  • TextField
  • Checkbox
  • Radio
  • Switch
  • Slider
  • 日付と時刻のピッカー
  • SimpleDialog
  • AlertDialog

最もよく使用されるクパチーノウィジェットのいくつかは次のとおりです-

  • CupertinoButton
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoTimerPicker
  • CupertinoNavigationBar
  • CupertinoTabBar
  • CupertinoTabScaffold
  • CupertinoTabView
  • CupertinoTextField
  • CupertinoDialog
  • CupertinoDialogAction
  • CupertinoFullscreenDialogTransition
  • CupertinoPageScaffold
  • CupertinoPageTransition
  • CupertinoActionSheet
  • CupertinoActivityIndicator
  • CupertinoAlertDialog
  • CupertinoPopupSurface
  • CupertinoSlider

レイアウトウィジェット

Flutterでは、1つ以上のウィジェットを作成することでウィジェットを作成できます。複数のウィジェットを1つのウィジェットに構成するために、Flutterはレイアウト機能を備えた多数のウィジェットを提供します。たとえば、子ウィジェットは、中央ウィジェットを使用して中央に配置できます。

人気のあるレイアウトウィジェットのいくつかは次のとおりです-

  • Container−背景、境界線、影付きのBoxDecorationウィジェットを使用して装飾された長方形のボックス。

  • Center −子ウィジェットを中央に配置します。

  • Row −子を水平方向に配置します。

  • Column −子を垂直方向に配置します。

  • Stack −上下に配置します。

レイアウトウィジェットの詳細については、次の「レイアウトウィジェットの概要」の章で確認します。

状態メンテナンスウィジェット

Flutterでは、すべてのウィジェットはStatelessWidgetまたはStatefulWidgetから派生しています。

StatelessWidgetから派生したウィジェットには状態情報はありませんが、StatefulWidgetから派生したウィジェットが含まれている可能性があります。アプリケーションの動的な性質は、ウィジェットの対話型の動作と、対話中に状態が変化することによるものです。たとえば、カウンターボタンをタップすると、カウンターの内部状態が1つ増減し、Flutterウィジェットの反応性により、新しい状態情報を使用してウィジェットが自動的に再レン​​ダリングされます。

StatefulWidgetウィジェットの概念については、次の状態管理の章で詳しく学習します。

プラットフォームに依存しない/基本的なウィジェット

Flutterは、プラットフォームに依存しない方法で単純なユーザーインターフェイスと複雑なユーザーインターフェイスを作成するための多数の基本的なウィジェットを提供します。この章の基本的なウィジェットのいくつかを見てみましょう。

Text

テキストウィジェットは、文字列の一部を表示するために使用されます。文字列のスタイルは、styleプロパティとTextStyleクラスを使用して設定できます。この目的のサンプルコードは次のとおりです-

Text('Hello World!', style: TextStyle(fontWeight: FontWeight.bold))

テキストの特別なコンストラクタを持っているウィジェットは、Text.richタイプの子受け付け、TextSpanは異なるスタイルで文字列を指定します。TextSpanウィジェットは本質的に再帰的であり、TextSpanを子として受け入れます。この目的のサンプルコードは次のとおりです-

Text.rich( 
   TextSpan( 
      children: <TextSpan>[ 
         TextSpan(text: "Hello ", style:  
         TextStyle(fontStyle: FontStyle.italic)),  
         TextSpan(text: "World", style: 
         TextStyle(fontWeight: FontWeight.bold)),  
      ], 
   ), 
)

テキストウィジェットの最も重要なプロパティは次のとおりです-

  • maxLines, int −表示する最大行数

  • overflow, TextOverFlow−TextOverFlowクラスを使用してビジュアルオーバーフローを処理する方法を指定します

  • style, TextStyle−TextStyleクラスを使用して文字列のスタイルを指定します

  • textAlign, TextAlignTextAlignクラスを使用した、右、左、両端揃えなどのテキストの配置

  • textDirection, TextDirection −テキストの流れの方向(左から右または右から左)

Image

画像ウィジェットは、アプリケーションで画像を表示するために使用されます。画像ウィジェットは、複数のソースから画像をロードするためのさまざまなコンストラクターを提供します。それらは次のとおりです。

  • Image−ImageProviderを使用した汎用イメージローダー

  • Image.asset −フラッタープロジェクトのアセットから画像をロードする

  • Image.file −システムフォルダから画像をロードする

  • Image.memory −メモリから画像をロードする

  • Image.Network −ネットワークから画像をロードする

Flutterで画像を読み込んで表示する最も簡単なオプションは、画像をアプリケーションのアセットとして含め、オンデマンドでウィジェットに読み込むことです。

  • プロジェクトフォルダにアセットを作成し、必要な画像を配置します。

  • 以下に示すように、pubspec.yamlでアセットを指定します-

flutter: 
   assets: 
      - assets/smiley.png
  • 次に、アプリケーションに画像を読み込んで表示します。

Image.asset('assets/smiley.png')
  • helloworldアプリケーションのMyHomePageウィジェットの完全なソースコードと結果は次のとおりです-。

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( title: Text(this.title), ), 
         body: Center( child: Image.asset("assets/smiley.png")),
      ); 
   }
}

ロードされた画像は以下のようになります-

画像ウィジェットの最も重要なプロパティは次のとおりです-

  • image, ImageProvider −ロードする実際の画像

  • width, double −画像の幅

  • height, double −画像の高さ

  • alignment, AlignmentGeometry −画像をその境界内に配置する方法

Icon

アイコンウィジェットは、IconDataクラスで記述されたフォントのグリフを表示するために使用されます。簡単なメールアイコンをロードするコードは次のとおりです-

Icon(Icons.email)

helloworldアプリケーションに適用するための完全なソースコードは次のとおりです。

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center( child: Icon(Icons.email)),
      );
   }
}

ロードされたアイコンは以下のとおりです-

FlutterのコアコンセプトはすべてウィジェットであるためFlutterはユーザーインターフェイスのレイアウト機能をウィジェット自体に組み込んでいます。Flutterは、ユーザーインターフェイスをレイアウトする目的でのみ、Container、Center、Alignなどの特別に設計されたウィジェットを多数提供します。他のウィジェットを構成することによって構築されるウィジェットは、通常、レイアウトウィジェットを使用します。この章でフラッターレイアウトの概念を学びましょう。

レイアウトウィジェットの種類

レイアウトウィジェットは、その子に基づいて2つの異なるカテゴリにグループ化できます-

  • 一人っ子をサポートするウィジェット
  • 複数の子をサポートするウィジェット

次のセクションでは、ウィジェットのタイプとその機能の両方を学びましょう。

シングルチャイルドウィジェット

このカテゴリでは、ウィジェットの子としてウィジェットが1つだけになり、すべてのウィジェットに特別なレイアウト機能があります。

たとえば、センターウィジェットは、親ウィジェットに対して子ウィジェットを中央に配置するだけであり、コンテナウィジェットは、パディング、装飾などのさまざまなオプションを使用して、子ウィジェットをその中の任意の場所に配置する完全な柔軟性を提供します。

単一の子ウィジェットは、ボタン、ラベルなどの単一の機能を備えた高品質のウィジェットを作成するための優れたオプションです。

コンテナウィジェットを使用して単純なボタンを作成するコードは次のとおりです-

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

ここでは、コンテナウィジェットとテキストウィジェットの2つのウィジェットを使用しました。ウィジェットの結果は、以下に示すようにカスタムボタンとして表示されます-

Flutterが提供する最も重要なシングルチャイルドレイアウトウィジェットのいくつかを確認しましょう-

  • Padding−指定されたパディングによって子ウィジェットを配置するために使用されます。ここで、パディングはEdgeInsetsクラスによって提供できます。

  • Alignアライメントプロパティの値を使用して、子ウィジェットをそれ自体の中で整列させます。配置プロパティの値は、FractionalOffsetクラスによって提供できます。FractionalOffsetのクラスは、左上からの距離の面でオフセットを指定します。

オフセットの可能な値のいくつかは次のとおりです-

  • FractionalOffset(1.0、0.0)は右上を表します。

  • FractionalOffset(0.0、1.0)は左下を表します。

オフセットに関するサンプルコードを以下に示します-

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox −子ウィジェットをスケーリングし、指定されたフィットに従って配置します。

  • AspectRatio −指定されたアスペクト比に子ウィジェットのサイズを設定しようとします

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

私たちのhelloworldアプリケーションは、マテリアルベースのレイアウトウィジェットを使用してホームページをデザインしています。以下に指定する基本的なレイアウトウィジェットを使用してホームページを構築するように、HelloWorldアプリケーションを変更してみましょう-

  • Container −豊富なスタイリング機能に加えて、配置、パディング、境界線、マージンを備えた、汎用のシングルチャイルドボックスベースのコンテナウィジェット。

  • Center −子ウィジェットを中央に配置するシンプルな単一の子コンテナウィジェット。

MyHomePageおよびMyAppウィジェットの変更されたコードは次のとおりです-

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

ここに、

  • コンテナウィジェットは、トップレベルまたはルートウィジェットです。コンテナは、そのコンテンツをレイアウトするために装飾およびパディングプロパティを使用して構成されます。

  • BoxDecorationには、コンテナウィジェットを装飾するための色、境界線などの多くのプロパティがあります。ここでは、を使用してコンテナの色を設定します。

  • コンテナウィジェットのパディングは、パディング値を指定するオプションを提供するdgeInsetsクラスを使用して設定されます。

  • Centerは、コンテナウィジェットの子ウィジェットです。繰り返しますが、TextCenterウィジェットの子です。テキストはメッセージを表示するために使用され、Centerは親ウィジェットContainerに関してテキストメッセージを中央に配置するために使用されます。

上記のコードの最終結果は、以下に示すレイアウトサンプルです。

複数の子ウィジェット

このカテゴリでは、特定のウィジェットに複数の子ウィジェットがあり、各ウィジェットのレイアウトは一意です。

たとえば、ウィジェットでは子を水平方向にレイアウトできますが、ウィジェットでは子を垂直方向にレイアウトできます。列を構成することにより、あらゆるレベルの複雑さを持つウィジェットを構築できます。

このセクションでは、頻繁に使用されるウィジェットのいくつかを学びましょう。

  • Row −子を水平に配置できます。

  • Column −子を垂直に配置できます。

  • ListView −子をリストとして配置できます。

  • GridView −子をギャラリーとして配置できます。

  • Expanded −行ウィジェットと列ウィジェットの子が可能な最大領域を占めるようにするために使用されます。

  • Table −テーブルベースのウィジェット。

  • Flow −フローベースのウィジェット。

  • Stack −スタックベースのウィジェット。

高度なレイアウトアプリケーション

このセクションでは、単一の子レイアウトウィジェットと複数の子レイアウトウィジェットの両方を使用して、カスタムデザインで製品リストの複雑なユーザーインターフェイスを作成する方法を学びましょう。

この目的のために、以下に示す順序に従ってください-

  • AndroidStudioで新しいFlutterアプリケーションproduct_layout_appを作成します。

  • main.dartコードを次のコードに置き換えます-

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • デフォルトのStatefulWidgetの代わりにStatelessWidgetを拡張してMyHomePageウィジェットを作成し、関連するコードを削除しました。

  • 次に、以下に示すように、指定されたデザインに従って新しいウィジェットProductBoxを作成します-

  • ProductBoxのコードは次のとおりです。

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • コードで次のことを守ってください-

  • ProductBoxは、以下に指定されている4つの引数を使用しています-

    • 名前-製品名

    • 説明-製品の説明

    • 価格-製品の価格

    • 画像-製品の画像

  • ProductBoxは、以下に指定されている7つの組み込みウィジェットを使用します-

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBoxは、上記のウィジェットを使用して設計されています。ウィジェットの配置または階層は、以下に示す図で指定されています-

  • 次に、製品情報のダミーイメージ(以下を参照)をアプリケーションのassetsフォルダーに配置し、以下に示すようにpubspec.yamlファイルのassetsフォルダーを構成します。

assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png

iPhone.png

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

最後に、使用ProductBoxはウィジェットMyHomePage以下の指定されたウィジェット-

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • ここでは、ProductBoxListViewウィジェットの子として使用しました

  • 製品レイアウトアプリケーション(product_layout_app)の完全なコード(main.dart)は次のとおりです-

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

アプリケーションの最終出力は次のとおりです-

ジェスチャは、主にユーザーがモバイル(またはタッチベースのデバイス)アプリケーションと対話するための方法です。ジェスチャは、一般に、モバイルデバイスの特定のコントロールをアクティブにすることを目的としたユーザーの物理的なアクション/動きとして定義されます。ジェスチャは、モバイルデバイスの画面をタップするだけで、ゲームアプリケーションで使用されるより複雑なアクションを実行できます。

広く使用されているジェスチャーのいくつかをここで説明します-

  • Tap −デバイスの表面に指先で短時間触れてから、指先を離します。

  • Double Tap −短時間で2回たたく。

  • Drag −指先でデバイスの表面に触れ、次に指先を安定して動かし、最後に指先を離します。

  • Flick −ドラッグに似ていますが、より高速な方法で実行します。

  • Pinch −2本の指でデバイスの表面をつまむ。

  • Spread/Zoom −つまむの反対。

  • Panning −指先でデバイスの表面に触れ、指先を離さずに任意の方向に動かします。

Flutterは、専用のウィジェットを通じて、あらゆる種類のジェスチャーに優れたサポートを提供します。 GestureDetector。GestureDetectorは、主にユーザーのジェスチャを検出するために使用される非ビジュアルウィジェットです。ウィジェットを対象とするジェスチャを識別するために、ウィジェットをGestureDetectorウィジェット内に配置できます。GestureDetectorはジェスチャをキャプチャし、ジェスチャに基づいて複数のイベントをディスパッチします。

ジェスチャーの一部と対応するイベントを以下に示します-

  • Tap
    • onTapDown
    • onTapUp
    • onTap
    • onTapCancel
  • ダブルタップ
    • onDoubleTap
  • 長押し
    • onLongPress
  • 垂直ドラッグ
    • onVerticalDragStart
    • onVerticalDragUpdate
    • onVerticalDragEnd
  • 水平方向のドラッグ
    • onHorizontalDragStart
    • onHorizontalDragUpdate
    • onHorizontalDragEnd
  • Pan
    • onPanStart
    • onPanUpdate
    • onPanEnd

それでは、ジェスチャー検出機能を含むようにhello worldアプリケーションを変更して、概念を理解してみましょう。

  • 以下に示すように、MyHomePageウィジェットの本文コンテンツを変更します-

body: Center( 
   child: GestureDetector( 
      onTap: () { 
         _showDialog(context); 
      }, 
      child: Text( 'Hello World', ) 
   ) 
),
  • ここでは、GestureDetectorウィジェットをウィジェット階層のTextウィジェットの上に配置し、onTapイベントをキャプチャして、最後にダイアログウィンドウを表示していることを確認してください。

  • * _showDialog *関数を実装して、ユーザーがhelloworldメッセージをタブで移動したときにダイアログを表示します。一般的なshowDialogウィジェットとAlertDialogウィジェットを使用して、新しいダイアログウィジェットを作成します。コードを以下に示します-

// user defined function void _showDialog(BuildContext context) { 
   // flutter defined function 
   showDialog( 
      context: context, builder: (BuildContext context) { 
         // return object of type Dialog
         return AlertDialog( 
            title: new Text("Message"), 
            content: new Text("Hello World"),   
            actions: <Widget>[ 
               new FlatButton( 
                  child: new Text("Close"),  
                  onPressed: () {   
                     Navigator.of(context).pop();  
                  }, 
               ), 
            ], 
         ); 
      }, 
   ); 
}
  • アプリケーションは、ホットリロード機能を使用してデバイスにリロードします。ここで、Hello Worldというメッセージをクリックするだけで、次のようなダイアログが表示されます-

  • 次に、ダイアログの閉じるオプションをクリックして、ダイアログを閉じます。

  • 完全なコード(main.dart)は次のとおりです-

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application.    
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application', 
         theme: ThemeData( primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   // user defined function 
   void _showDialog(BuildContext context) { 
      // flutter defined function showDialog( 
         context: context, builder: (BuildContext context) { 
            // return object of type Dialog return AlertDialog(
               title: new Text("Message"), 
               content: new Text("Hello World"),   
               actions: <Widget>[
                  new FlatButton(
                     child: new Text("Close"), 
                     onPressed: () {   
                        Navigator.of(context).pop();  
                     }, 
                  ), 
               ],
            );
         },
      );
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center(
            child: GestureDetector( 
               onTap: () {
                  _showDialog(context);
               },
            child: Text( 'Hello World', )
            )
         ),
      );
   }
}

最後に、Flutterは、リスナーウィジェットを介して低レベルのジェスチャ検出メカニズムも提供します。すべてのユーザーインタラクションを検出し、次のイベントをディスパッチします-

  • PointerDownEvent
  • PointerMoveEvent
  • PointerUpEvent
  • PointerCancelEvent

Flutterは、特定のジェスチャと高度なジェスチャを実行するためのウィジェットの小さなセットも提供します。ウィジェットは以下のとおりです-

  • Dismissible −ウィジェットを閉じるためのフリックジェスチャをサポートします。

  • Draggable −ウィジェットを移動するためのドラッグジェスチャをサポートします。

  • LongPressDraggable −親ウィジェットもドラッグ可能である場合に、ウィジェットを移動するためのドラッグジェスチャをサポートします。

  • DragTargetドラッグ可能なウィジェットを受け入れます

  • IgnorePointer −ウィジェットとその子をジェスチャ検出プロセスから非表示にします。

  • AbsorbPointer −ジェスチャ検出プロセス自体を停止するため、重複するウィジェットもジェスチャ検出プロセスに参加できず、イベントは発生しません。

  • Scrollable −ウィジェット内で利用可能なコンテンツのスクロールをサポートします。

アプリケーションの状態を管理することは、アプリケーションのライフサイクルにおいて最も重要で必要なプロセスの1つです。

簡単なショッピングカートアプリケーションについて考えてみましょう。

  • ユーザーは、自分の資格情報を使用してアプリケーションにログインします。

  • ユーザーがログインすると、アプリケーションはログインしたユーザーの詳細をすべての画面に保持する必要があります。

  • この場合も、ユーザーが商品を選択してカートに保存すると、ユーザーがカートをチェックアウトするまで、カート情報はページ間で保持されます。

  • 任意のインスタンスでのユーザーとそのカート情報は、そのインスタンスでのアプリケーションの状態と呼ばれます。

状態管理は、特定の状態がアプリケーションで持続する期間に基づいて2つのカテゴリに分類できます。

  • Ephemeral−アニメーションの現在の状態のように数秒間続くか、製品の現在の評価のように1ページ続きます。FlutterはStatefulWidgetを介してそれをサポートします。

  • app state−ログインしたユーザーの詳細、カート情報など、アプリケーション全体で最後に、Flutterはscoped_modelを介してサポートします。

ナビゲーションとルーティング

どのアプリケーションでも、あるページ/画面から別のページに移動すると、アプリケーションのワークフローが定義されます。アプリケーションのナビゲーションが処理される方法は、ルーティングと呼ばれます。Flutterは、アプリケーションのワークフローを定義するために、基本的なルーティングクラスであるMaterialPageRouteと2つのメソッドであるNavigator.pushとNavigator.popを提供します。

MaterialPageRoute

MaterialPageRouteは、画面全体をプラットフォーム固有のアニメーションに置き換えることでUIをレンダリングするために使用されるウィジェットです。

MaterialPageRoute(builder: (context) => Widget())

ここで、ビルダーは、アプリケーションの現在のコンテキストを提供することにより、コンテンツをビルドする関数を受け入れます。

Navigation.push

Navigation.pushは、MaterialPageRouteウィジェットを使用して新しい画面に移動するために使用されます。

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

Navigation.pop

Navigation.popは、前の画面に移動するために使用されます。

Navigator.pop(context);

ナビゲーションの概念をよりよく理解するために、新しいアプリケーションを作成しましょう。

AndroidStudioで新しいFlutterアプリケーションproduct_nav_appを作成します

  • アセットフォルダーをproduct_nav_appからproduct_state_appにコピーし、pubspec.yamlファイル内にアセットを追加します。

flutter:
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • デフォルトのスタートアップコード(main.dart)をスタートアップコードに置き換えます。

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) { 
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Product state demo home page'
         ),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: Text('Hello World',)
         ), 
      ); 
   } 
}
  • 製品情報を整理するためのProductクラスを作成しましょう。

class Product { 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
}
  • ProductクラスにメソッドgetProductsを記述して、ダミーの製品レコードを生成しましょう。

static List<Product> getProducts() {
   List<Product> items = <Product>[]; 
   
   items.add(
      Product( 
         "Pixel", 
         "Pixel is the most feature-full phone ever", 800, 
         "pixel.png"
      )
   ); 
   items.add(
      Product(
         "Laptop", 
         "Laptop is most productive development tool", 
         2000, "
         laptop.png"
      )
   ); 
   items.add(
      Product( 
         "Tablet", 
         "Tablet is the most useful device ever for meeting", 
         1500, 
         "tablet.png"
      )
   ); 
   items.add(
      Product( 
         "Pendrive", 
         "Pendrive is useful storage medium",
         100, 
         "pendrive.png"
      )
   ); 
   items.add(
      Product( 
         "Floppy Drive", 
         "Floppy drive is useful rescue storage medium", 
         20, 
         "floppy.png"
      )
   ); 
   return items; 
}
import product.dart in main.dart
import 'Product.dart';
  • 新しいウィジェット、RatingBoxを含めましょう。

class RatingBox extends StatefulWidget {
   @override 
   _RatingBoxState createState() =>_RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> {
   int _rating = 0; 
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   } 
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   }
   void _setRatingAsThree() {
      setState(() {
         _rating = 3;
      });
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 2? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   }
}
  • ProductBoxウィジェットを変更して、新しいProductクラスで動作するようにしましょう。

class ProductBox extends StatelessWidget {    
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), 
                        child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[
                              Text(this.item.name, 
                              style: TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   }
}

MyHomePageウィジェットを書き直して、Productモデルを操作し、ListViewを使用してすべての製品を一覧表示しましょう。

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( appBar: AppBar(title: Text("Product Navigation")), 
      body: ListView.builder( 
         itemCount: items.length, 
         itemBuilder: (context, index) {
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push( 
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      )); 
   } 
}

ここでは、MaterialPageRouteを使用して製品の詳細ページに移動しました。

  • それでは、ProductPageを追加して、製品の詳細を表示しましょう。

class ProductPage extends StatelessWidget { 
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container(
               padding: EdgeInsets.all(0), 
               child: Column(
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded(
                        child: Container(
                           padding: EdgeInsets.all(5), 
                           child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[
                                 Text(
                                    this.item.name, style: TextStyle(
                                       fontWeight: FontWeight.bold
                                    )
                                 ), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(),
                              ], 
                           )
                        )
                     )
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}

アプリケーションの完全なコードは次のとおりです-

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class Product {
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
   
   static List<Product> getProducts() {
      List<Product> items = <Product>[]; 
      items.add(
         Product(
            "Pixel", 
            "Pixel is the most featureful phone ever", 
            800, 
            "pixel.png"
         )
      );
      items.add(
         Product(
            "Laptop", 
            "Laptop is most productive development tool", 
            2000, 
            "laptop.png"
         )
      ); 
      items.add(
         Product(
            "Tablet", 
            "Tablet is the most useful device ever for meeting", 
            1500, 
            "tablet.png"
         )
      ); 
      items.add(
         Product( 
            "Pendrive", 
            "iPhone is the stylist phone ever", 
            100, 
            "pendrive.png"
         )
      ); 
      items.add(
         Product(
            "Floppy Drive", 
            "iPhone is the stylist phone ever", 
            20, 
            "floppy.png"
         )
      ); 
      items.add(
         Product(
            "iPhone", 
            "iPhone is the stylist phone ever", 
            1000, 
            "iphone.png"
         )
      ); 
      return items; 
   }
}
class MyApp extends StatelessWidget {
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Product Navigation demo home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: ListView.builder( 
            itemCount: items.length, 
            itemBuilder: (context, index) { 
               return GestureDetector( 
                  child: ProductBox(item: items[index]), 
                  onTap: () { 
                     Navigator.push( 
                        context, 
                        MaterialPageRoute( 
                           builder: (context) => ProductPage(item: items[index]), 
                        ), 
                     ); 
                  }, 
               ); 
            }, 
         )
      ); 
   }
} 
class ProductPage extends StatelessWidget {
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container( 
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[ 
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() => _RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0;
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   } 
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1 ? Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 2 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     )
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
} 
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  ) 
               ]
            ), 
         )
      ); 
   } 
}

アプリケーションを実行し、製品アイテムのいずれかをクリックします。関連する詳細ページが表示されます。戻るボタンをクリックするとホームページに移動できます。アプリケーションの製品リストページと製品詳細ページは次のように表示されます-

アニメーションは、どのモバイルアプリケーションでも複雑な手順です。アニメーションはその複雑さにもかかわらず、ユーザーエクスペリエンスを新しいレベルに高め、豊富なユーザーインタラクションを提供します。その豊かさのために、アニメーションは現代のモバイルアプリケーションの不可欠な部分になります。Flutterフレームワークは、アニメーションの重要性を認識し、あらゆるタイプのアニメーションを開発するためのシンプルで直感的なフレームワークを提供します。

前書き

アニメーションは、一連の画像/画像を特定の期間内に特定の順序で表示して、動きの錯覚を与えるプロセスです。アニメーションの最も重要な側面は次のとおりです-

  • アニメーションには、開始値と終了値の2つの異なる値があります。アニメーションは開始値から始まり、一連の中間値を経て、最後に終了値で終了します。たとえば、ウィジェットをアニメーション化してフェードアウトさせる場合、初期値は完全な不透明度になり、最終値はゼロの不透明度になります。

  • 中間値は、本質的に線形または非線形(曲線)であり、構成することができます。アニメーションが構成どおりに機能することを理解します。各構成は、アニメーションに異なる感触を提供します。たとえば、ウィジェットのフェードは本質的に線形になりますが、ボールのバウンスは本質的に非線形になります。

  • アニメーションプロセスの期間は、アニメーションの速度(遅さまたは速さ)に影響します。

  • アニメーションの開始、アニメーションの停止、アニメーションを繰り返して設定回数にする、アニメーションのプロセスを逆にするなど、アニメーションプロセスを制御する機能。

  • Flutterでは、アニメーションシステムは実際のアニメーションを実行しません。代わりに、画像をレンダリングするためにすべてのフレームで必要な値のみを提供します。

アニメーションベースのクラス

フラッターアニメーションシステムは、アニメーションオブジェクトに基づいています。コアアニメーションクラスとその使用法は次のとおりです-

アニメーション

特定の期間にわたって2つの数値の間で補間された値を生成します。最も一般的なアニメーションクラスは次のとおりです。

  • Animation<double> −2つの10進数の間の値を補間します

  • Animation<Color> −2つの色の間で色を補間する

  • Animation<Size> −2つのサイズの間でサイズを補間する

  • AnimationController−アニメーション自体を制御するための特別なアニメーションオブジェクト。アプリケーションが新しいフレームの準備ができるたびに、新しい値を生成します。線形ベースのアニメーションをサポートし、値は0.0から1.0で始まります

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this);

ここで、コントローラーはアニメーションを制御し、期間オプションはアニメーションプロセスの期間を制御します。vsyncは、アニメーションで使用されるリソースを最適化するために使用される特別なオプションです。

CurvedAnimation

AnimationControllerに似ていますが、非線形アニメーションをサポートします。CurvedAnimationは、以下のようにAnimationオブジェクトと一緒に使用できます-

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)

トゥイーン<T>

Animatable <T>から派生し、0と1以外の任意の2つの数値の間の数値を生成するために使用されます。animateメソッドを使用して実際のAnimationオブジェクトを渡すことにより、Animationオブジェクトと一緒に使用できます。

AnimationController controller = AnimationController( 
   duration: const Duration(milliseconds: 1000), 
vsync: this); Animation<int> customTween = IntTween(
   begin: 0, end: 255).animate(controller);
  • Tweenは、以下のようにCurvedAnimationと一緒に使用することもできます-

AnimationController controller = AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this); 
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); 
Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve);

ここで、コントローラーは実際のアニメーションコントローラーです。曲線は非線形性のタイプを提供し、customTweenは0から255までのカスタム範囲を提供します。

Flutterアニメーションのワークフロー

アニメーションのワークフローは以下の通りです−

  • StatefulWidgetのinitStateでアニメーションコントローラーを定義して開始します。

AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = Tween<double>(begin: 0, end: 300).animate(controller); 
controller.forward();
  • アニメーションベースのリスナー、addListenerを追加して、ウィジェットの状態を変更します。

animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
   setState(() { 
      // The state that has changed here is the animation object’s value. 
   }); 
});
  • 組み込みウィジェット、AnimatedWidgetおよびAnimatedBuilderを使用して、このプロセスをスキップできます。どちらのウィジェットもAnimationオブジェクトを受け入れ、アニメーションに必要な現在の値を取得します。

  • ウィジェットのビルドプロセス中にアニメーション値を取得し、元の値の代わりに幅、高さ、または関連するプロパティに適用します。

child: Container( 
   height: animation.value, 
   width: animation.value, 
   child: <Widget>, 
)

実用的なアプリケーション

Flutterフレームワークのアニメーションの概念を理解するために、簡単なアニメーションベースのアプリケーションを作成しましょう。

  • AndroidStudioで新しいFlutterアプリケーションproduct_animation_appを作成します。

  • アセットフォルダーをproduct_nav_appからproduct_animation_appにコピーし、pubspec.yamlファイル内にアセットを追加します。

flutter: 
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • デフォルトのスタートアップコード(main.dart)を削除します。

  • インポートと基本的なメイン機能を追加します。

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());
  • StatefulWidgtetから派生したMyAppウィジェットを作成します。

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
}
  • デフォルトのビルドメソッドに加えて、_MyAppStateウィジェットを作成し、initStateを実装して破棄します。

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { 
   Animation<double> animation; 
   AnimationController controller; 
   @override void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this
      ); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose();
   }
}

ここに、

  • initStateメソッドでは、アニメーションコントローラーオブジェクト(コントローラー)、アニメーションオブジェクト(アニメーション)を作成し、controller.forwardを使用してアニメーションを開始しました。

  • disposeメソッドでは、アニメーションコントローラーオブジェクト(コントローラー)を破棄しました。

  • buildメソッドで、コンストラクターを介してアニメーションをMyHomePageウィジェットに送信します。これで、MyHomePageウィジェットはアニメーションオブジェクトを使用してそのコンテンツをアニメーション化できます。

  • 次に、ProductBoxウィジェットを追加します

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image})
      : super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row( 
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.name, style: 
                                 TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.description), 
                                 Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      ); 
   }
}
  • 新しいウィジェットMyAnimatedWidgetを作成して、不透明度を使用して単純なフェードアニメーションを実行します。

class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
      
   final Widget child; 
   final Animation<double> animation; 
   
   Widget build(BuildContext context) => Center( 
   child: AnimatedBuilder(
      animation: animation, 
      builder: (context, child) => Container( 
         child: Opacity(opacity: animation.value, child: child), 
      ), 
      child: child), 
   ); 
}
  • ここでは、AniatedBuilderを使用してアニメーションを作成しました。AnimatedBuilderは、アニメーションを実行しながらコンテンツを作成するウィジェットです。アニメーションオブジェクトを受け入れて、現在のアニメーション値を取得します。アニメーション値animation.valueを使用して、子ウィジェットの不透明度を設定しました。事実上、ウィジェットは不透明度の概念を使用して子ウィジェットをアニメーション化します。

  • 最後に、MyHomePageウィジェットを作成し、アニメーションオブジェクトを使用してそのコンテンツをアニメーション化します。

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title, this.animation}) : super(key: key); 
   
   final String title; 
   final Animation<double> 
   animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")),body: ListView(
            shrinkWrap: true,
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), opacity: animation
               ), 
               MyAnimatedWidget(child: ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), animation: animation), 
               ProductBox(
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ),
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ),
            ],
         )
      );
   }
}

ここでは、FadeAnimationとMyAnimationWidgetを使用して、リストの最初の2つのアイテムをアニメーション化しました。FadeAnimationは組み込みのアニメーションクラスであり、不透明度の概念を使用して子をアニメーション化するために使用しました。

  • 完全なコードは次のとおりです-

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
} 
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
   Animation<double> animation; 
   AnimationController controller; 
   
   @override 
   void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,) 
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose(); 
   } 
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title, this.animation}): super(key: key);
   final String title; 
   final Animation<double> animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), 
                  opacity: animation
               ), 
               MyAnimatedWidget(
                  child: ProductBox( 
                     name: "Pixel", 
                     description: "Pixel is the most featureful phone ever", 
                     price: 800, 
                     image: "pixel.png"
                  ), 
                  animation: animation
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet",
                  description: "Tablet is the most useful device ever for meeting",
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ], 
         )
      ); 
   } 
} 
class ProductBox extends StatelessWidget { 
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded(
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ), 
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  ) 
               ]
            )
         )
      ); 
   } 
}
class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
   final Widget child; 
   final Animation<double> animation; 
 
   Widget build(BuildContext context) => Center( 
      child: AnimatedBuilder(
         animation: animation, 
         builder: (context, child) => Container( 
            child: Opacity(opacity: animation.value, child: child), 
         ), 
         child: child
      ), 
   ); 
}
  • アプリケーションをコンパイルして実行し、結果を確認します。アプリケーションの初期バージョンと最終バージョンは次のとおりです-

Flutterは、プラットフォーム固有の機能にアクセスするための一般的なフレームワークを提供します。これにより、開発者はプラットフォーム固有のコードを使用してFlutterフレームワークの機能を拡張できます。カメラ、バッテリーレベル、ブラウザーなどのプラットフォーム固有の機能には、フレームワークを介して簡単にアクセスできます。

プラットフォーム固有のコードにアクセスする一般的な考え方は、単純なメッセージングプロトコルを使用することです。フラッターコード、クライアント、プラットフォームコード、およびホストは、共通のメッセージチャネルにバインドします。クライアントは、メッセージチャネルを介してホストにメッセージを送信します。ホストはメッセージチャネルでリッスンし、メッセージを受信して​​必要な機能を実行し、最後にメッセージチャネルを介して結果をクライアントに返します。

プラットフォーム固有のコードアーキテクチャは、以下のブロック図に示されています。

メッセージングプロトコルは、数値、文字列、ブール値などのJSONのような値のバイナリシリアル化をサポートする標準メッセージコーデック(StandardMessageCodecクラス)を使用します。シリアル化と逆シリアル化は、クライアントとホストの間で透過的に機能します。

Android SDKを使用してブラウザを開く簡単なアプリケーションを作成し、その方法を理解しましょう

  • AndroidStudioで新しいFlutterアプリケーションflutter_browser_appを作成します

  • main.dartコードを以下のコードに置き換えます-

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Flutter Demo Home Page'),
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: null, 
            ), 
         ), 
      ); 
   }
}
  • ここでは、ブラウザを開き、そのonPressedメソッドをnullに設定するための新しいボタンを作成しました。

  • ここで、次のパッケージをインポートします-

import 'dart:async'; 
import 'package:flutter/services.dart';
  • ここで、services.dartには、プラットフォーム固有のコードを呼び出す機能が含まれています。

  • MyHomePageウィジェットで新しいメッセージチャネルを作成します。

static const platform = const 
MethodChannel('flutterapp.tutorialspoint.com/browser');
  • メソッド、_openBrowserを記述してプラットフォーム固有のメソッドを呼び出し、メッセージチャネルを介してopenBrowserメソッドを記述します。

Future<void> _openBrowser() async { 
   try {
      final int result = await platform.invokeMethod(
         'openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         }
      ); 
   } 
   on PlatformException catch (e) { 
      // Unable to open the browser 
      print(e); 
   }
}

ここでは、platform.invokeMethodを使用してopenBrowserを呼び出しました(次の手順で説明します)。openBrowserには、特定のURLを開くための引数urlがあります。

  • RaisedButtonのonPressedプロパティの値をnullから_openBrowserに変更します。

onPressed: _openBrowser,
  • MainActivity.java(androidフォルダー内)を開き、必要なライブラリをインポートします-

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant;
  • ブラウザを開くためのメソッドopenBrowserを記述します

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = this; 
   if (activity == null) { 
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground 
      activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • ここで、MainActivityクラスにチャネル名を設定します-

private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser";
  • onCreateメソッドでメッセージ処理を設定するAndroid固有のコードを記述します-

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( 
   new MethodCallHandler() { 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("openBrowser")) {
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
});

ここでは、MethodChannelクラスを使用してメッセージチャネルを作成し、MethodCallHandlerクラスを使用してメッセージを処理しました。onMethodCallは、メッセージをチェックすることによって正しいプラットフォーム固有のコードを呼び出すための実際のメソッドです。onMethodCallメソッドは、メッセージからURLを抽出し、メソッド呼び出しがopenBrowserの場合にのみopenBrowserを呼び出します。それ以外の場合は、notImplementedメソッドを返します。

アプリケーションの完全なソースコードは次のとおりです-

main.dart

MainActivity.java

package com.tutorialspoint.flutterapp.flutter_browser_app; 

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant; 

public class MainActivity extends FlutterActivity { 
   private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser"; 
   @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      GeneratedPluginRegistrant.registerWith(this); 
      new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
         new MethodCallHandler() {
            @Override 
            public void onMethodCall(MethodCall call, Result result) {
               String url = call.argument("url"); 
               if (call.method.equals("openBrowser")) { 
                  openBrowser(call, result, url); 
               } else { 
                  result.notImplemented(); 
               }
            }
         }
      ); 
   }
   private void openBrowser(MethodCall call, Result result, String url) {
      Activity activity = this; if (activity == null) {
         result.error(
            "ACTIVITY_NOT_AVAILABLE", "Browser cannot be opened without foreground activity", null
         ); 
         return; 
      } 
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   }
}

main.dart

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'package:flutter/services.dart'; 

void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget {
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   static const platform = const MethodChannel('flutterapp.tutorialspoint.com/browser'); 
   Future<void> _openBrowser() async {
      try {
         final int result = await platform.invokeMethod('openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         });
      }
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      } 
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton( 
               child: Text('Open Browser'), 
               onPressed: _openBrowser, 
            ), 
         ),
      );
   }
}

アプリケーションを実行し、[ブラウザを開く]ボタンをクリックすると、ブラウザが起動していることがわかります。ブラウザアプリ-ホームページはここのスクリーンショットに示されているとおりです-

iOS固有のコードへのアクセスは、iOS固有の言語(Objective-CまたはSwiftとiOS SDK)を使用することを除いて、Androidプラットフォームのコードと似ています。それ以外の点では、コンセプトはAndroidプラットフォームのコンセプトと同じです。

iOSプラットフォームについても前章と同じアプリケーションを書いてみましょう。

  • Android Studio(macOS)で新しいアプリケーションflutter_browser_ios_appを作成しましょう

  • 前の章と同様に、手順2〜6に従います。

  • XCodeを起動し、をクリックします File → Open

  • flutterプロジェクトのiosディレクトリの下にあるxcodeプロジェクトを選択します。

  • 下のAppDelegate.mを開きます Runner → Runner path。次のコードが含まれています-

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      // [GeneratedPluginRegistrant registerWithRegistry:self];
      // Override point for customization after application launch.
      return [super application:application didFinishLaunchingWithOptions:launchOptions];
   } 
@end
  • 指定されたURLでブラウザを開くためのメソッドopenBrowserを追加しました。単一の引数urlを受け入れます。

- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
}
  • didFinishLaunchingWithOptionsメソッドで、コントローラーを見つけてコントローラー変数に設定します。

FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
  • didFinishLaunchingWithOptionsメソッドで、ブラウザチャネルをflutterapp.tutorialspoint.com/browse −として設定します。

FlutterMethodChannel* browserChannel = [
   FlutterMethodChannel methodChannelWithName:
   @"flutterapp.tutorialspoint.com/browser" binaryMessenger:controller];
  • 変数weakSelfを作成し、現在のクラスを設定します-

__weak typeof(self) weakSelf = self;
  • ここで、setMethodCallHandlerを実装します。call.methodを照合してopenBrowserを呼び出します。call.argumentsを呼び出してURLを取得し、openBrowserの呼び出し中にそれを渡します。

[browserChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
   if ([@"openBrowser" isEqualToString:call.method]) { 
      NSString *url = call.arguments[@"url"];   
      [weakSelf openBrowser:url]; 
   } else { result(FlutterMethodNotImplemented); } 
}];
  • 完全なコードは次のとおりです-

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application 
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
   // custom code starts 
   FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; 
   FlutterMethodChannel* browserChannel = [
      FlutterMethodChannel methodChannelWithName:
      @"flutterapp.tutorialspoint.com /browser" binaryMessenger:controller]; 
   
   __weak typeof(self) weakSelf = self; 
   [browserChannel setMethodCallHandler:^(
      FlutterMethodCall* call, FlutterResult result) { 
      
      if ([@"openBrowser" isEqualToString:call.method]) { 
         NSString *url = call.arguments[@"url"];
         [weakSelf openBrowser:url]; 
      } else { result(FlutterMethodNotImplemented); } 
   }]; 
   // custom code ends 
   [GeneratedPluginRegistrant registerWithRegistry:self]; 
   
   // Override point for customization after application launch. 
   return [super application:application didFinishLaunchingWithOptions:launchOptions]; 
}
- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
} 
@end
  • プロジェクト設定を開きます。

  • に移動 Capabilities 有効にします Background Modes

  • 追加 *Background fetch そして Remote Notification**

  • 次に、アプリケーションを実行します。Androidバージョンと同様に機能しますが、Chromeの代わりにSafariブラウザが開きます。

一連の機能を整理および共有するDartの方法は、Packageを使用することです。Dart Packageは、単に共有可能なライブラリまたはモジュールです。一般に、Dartパッケージにはアプリケーションエントリポイントmainがないことを除いて、DartパッケージはDartアプリケーションのパッケージと同じです。

パッケージの一般的な構造(デモパッケージmy_demo_packageを検討してください)は次のとおりです。

  • lib/src/* −プライベートDartコードファイル。

  • lib/my_demo_package.dart−メインのDartコードファイル。次のようにアプリケーションにインポートできます-

import 'package:my_demo_package/my_demo_package.dart'
  • 以下に示すように、必要に応じて、他のプライベートコードファイルをメインコードファイル(my_demo_package.dart)にエクスポートできます。

export src/my_private_code.dart
  • lib/*−任意のカスタムフォルダ構造に配置された任意の数のDartコードファイル。コードには、次のようにアクセスできます。

import 'package:my_demo_package/custom_folder/custom_file.dart'
  • pubspec.yaml −アプリケーションの仕様と同じプロジェクト仕様、

パッケージ内のすべてのDartコードファイルは単なるDartクラスであり、Dartコードがパッケージに含めるための特別な要件はありません。

パッケージの種類

Dartパッケージは基本的に同様の機能の小さなコレクションであるため、機能に基づいて分類できます。

ダートパッケージ

Web環境とモバイル環境の両方で使用できる汎用Dartコード。たとえば、english_wordsは、約5000語を含み、名詞(英語で名詞を一覧表示)、音節(1つの単語の音節数を指定)などの基本的なユーティリティ関数を備えたパッケージの1つです。

フラッターパッケージ

Flutterフレームワークに依存し、モバイル環境でのみ使用できる汎用Dartコード。たとえば、fluroはフラッター用のカスタムルーターです。Flutterフレームワークに依存します。

Flutterプラグイン

Flutterフレームワークと基盤となるプラットフォームコード(AndroidSDKまたはiOSSDK)に依存する汎用Dartコード。たとえば、cameraはデバイスのカメラと対話するためのプラグインです。カメラにアクセスするには、Flutterフレームワークと基盤となるフレームワークに依存します。

ダートパッケージの使用

Dartパッケージはホストされ、ライブサーバーに公開されます。 https://pub.dartlang.org.また、Flutterは、アプリケーションでDartパッケージを管理するためのシンプルなツールであるpubを提供します。パッケージとして使用するために必要な手順は次のとおりです-

  • 以下に示すように、パッケージ名と必要なバージョンをpubspec.yamlに含めます-

dependencies: english_words: ^3.1.5
  • 最新のバージョン番号は、オンラインサーバーを確認することで確認できます。

  • 次のコマンドを使用して、パッケージをアプリケーションにインストールします-

flutter packages get
  • Android Studioでの開発中に、Android Studioはpubspec.yamlの変更を検出し、以下に示すようにAndroidStudioパッケージアラートを開発者に表示します-

  • Dartパッケージは、メニューオプションを使用してAndroidStudioにインストールまたは更新できます。

  • 以下に示すコマンドを使用して必要なファイルをインポートし、作業を開始します-

import 'package:english_words/english_words.dart';
  • パッケージで利用可能な任意の方法を使用し、

nouns.take(50).forEach(print);
  • ここでは、名詞関数を使用して上位50語を取得して出力しました。

Flutterプラグインパッケージを開発する

Flutterプラグインの開発は、DartアプリケーションまたはDartパッケージの開発に似ています。唯一の例外は、プラグインがシステムAPI(AndroidまたはiOS)を使用して、必要なプラットフォーム固有の機能を取得することです。

前の章でプラットフォームコードにアクセスする方法をすでに学習したので、プラグイン開発プロセスを理解するために、単純なプラグインmy_browserを開発しましょう。my_browserプラグインの機能は、アプリケーションがプラットフォーム固有のブラウザーで特定のWebサイトを開くことができるようにすることです。

  • AndroidStudioを起動します。

  • クリック File → New Flutter Project FlutterPluginオプションを選択します。

  • ここに示すようなFlutterプラグイン選択ウィンドウが表示されます-

  • プロジェクト名としてmy_browserを入力し、[次へ]をクリックします。

  • ここに示すように、ウィンドウにプラグイン名とその他の詳細を入力します-

  • 以下に示すウィンドウに会社のドメインflutterplugins.tutorialspoint.comと入力し、をクリックします。 Finish。新しいプラグインを開発するためのスタートアップコードを生成します。

  • my_browser.dartファイルを開き、メソッドopenBrowserを記述して、プラットフォーム固有のopenBrowserメソッドを呼び出します。

Future<void> openBrowser(String urlString) async { 
   try {
      final int result = await _channel.invokeMethod(
         'openBrowser', <String, String>{ 'url': urlString }
      );
   }
   on PlatformException catch (e) { 
      // Unable to open the browser print(e); 
   } 
}
  • MyBrowserPlugin.javaファイルを開き、次のクラスをインポートします-

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle;
  • ここでは、Androidからブラウザを開くために必要なライブラリをインポートする必要があります。

  • MyBrowserPluginクラスにタイプRegistrarの新しいプライベート変数mRegistrarを追加します。

private final Registrar mRegistrar;
  • ここで、Registrarは、呼び出し元のコードのコンテキスト情報を取得するために使用されます。

  • MyBrowserPluginクラスにRegistrarを設定するコンストラクターを追加します。

private MyBrowserPlugin(Registrar registrar) { 
   this.mRegistrar = registrar; 
}
  • registerWithを変更して、MyBrowserPluginクラスに新しいコンストラクターを含めます。

public static void registerWith(Registrar registrar) { 
   final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_browser"); 
   MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
   channel.setMethodCallHandler(instance); 
}
  • onMethodCallを変更して、MyBrowserPluginクラスにopenBrowserメソッドを含めます。

@Override 
public void onMethodCall(MethodCall call, Result result) { 
   String url = call.argument("url");
   if (call.method.equals("getPlatformVersion")) { 
      result.success("Android " + android.os.Build.VERSION.RELEASE); 
   } 
   else if (call.method.equals("openBrowser")) { 
      openBrowser(call, result, url); 
   } else { 
      result.notImplemented(); 
   } 
}
  • MyBrowserPluginクラスのブラウザにアクセスするためのプラットフォーム固有のopenBrowserメソッドを記述します。

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = mRegistrar.activity(); 
   if (activity == null) {
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • my_browserプラグインの完全なソースコードは次のとおりです-

my_browser.dart

import 'dart:async'; 
import 'package:flutter/services.dart'; 

class MyBrowser {
   static const MethodChannel _channel = const MethodChannel('my_browser'); 
   static Future<String> get platformVersion async { 
      final String version = await _channel.invokeMethod('getPlatformVersion'); return version; 
   } 
   Future<void> openBrowser(String urlString) async { 
      try {
         final int result = await _channel.invokeMethod(
            'openBrowser', <String, String>{'url': urlString}); 
      } 
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      }
   }
}

MyBrowserPlugin.java

package com.tutorialspoint.flutterplugins.my_browser; 

import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugin.common.PluginRegistry.Registrar; 
import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

/** MyBrowserPlugin */ 
public class MyBrowserPlugin implements MethodCallHandler {
   private final Registrar mRegistrar; 
   private MyBrowserPlugin(Registrar registrar) { 
      this.mRegistrar = registrar; 
   } 
   /** Plugin registration. */
   public static void registerWith(Registrar registrar) {
      final MethodChannel channel = new MethodChannel(
         registrar.messenger(), "my_browser"); 
      MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
      channel.setMethodCallHandler(instance); 
   } 
   @Override 
   public void onMethodCall(MethodCall call, Result result) { 
      String url = call.argument("url"); 
      if (call.method.equals("getPlatformVersion")) { 
         result.success("Android " + android.os.Build.VERSION.RELEASE); 
      } 
      else if (call.method.equals("openBrowser")) { 
         openBrowser(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
   private void openBrowser(MethodCall call, Result result, String url) { 
      Activity activity = mRegistrar.activity(); 
      if (activity == null) {
         result.error("ACTIVITY_NOT_AVAILABLE",
            "Browser cannot be opened without foreground activity", null); 
         return; 
      }
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   } 
}
  • 新しいプロジェクトmy_browser_plugin_testを作成して、新しく作成したプラグインをテストします。

  • pubspec.yamlを開き、my_browserをプラグインの依存関係として設定します。

dependencies: 
   flutter: 
      sdk: flutter 
   my_browser: 
      path: ../my_browser
  • Android Studioは、以下に示すAndroidStudioパッケージアラートに示すようにpubspec.yamlが更新されたことをアラートします-

  • [依存関係の取得]オプションをクリックします。Android Studioはインターネットからパッケージを取得し、アプリケーション用に適切に構成します。

  • main.dartを開き、以下のようにmy_browserプラグインを含めます-

import 'package:my_browser/my_browser.dart';
  • 以下に示すように、my_browserプラグインからopenBrowser関数を呼び出します-

onPressed: () => MyBrowser().openBrowser("https://flutter.dev"),
  • main.dartの完全なコードは次のとおりです-

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

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

class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      );,
   }
} 
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton(
               child: Text('Open Browser'), 
               onPressed: () => MyBrowser().openBrowser("https://flutter.dev"), 
            ),
         ), 
      ); 
   }
}
  • アプリケーションを実行し、[ブラウザを開く]ボタンをクリックして、ブラウザが起動することを確認します。以下に示すスクリーンショットに示すように、ブラウザアプリ-ホームページを見ることができます-

以下に示すスクリーンショットに示すように、ブラウザアプリ–ブラウザ画面を見ることができます-

  • Print
  •  メモを追加
  •  このページをブックマークして
  •  エラーの報告
  •  Suggestions

保存 閉じる