株式会社INTSへようこそ

技術ブログ

  • Home
  • 技術ブログ

基本的なフラッター: Widget Tree、 Element Tree と Render Tree

このシリーズの前回の投稿を読んだ後、実際にどのようにwidgetを再構築する方法に疑問を抱いているかと思います。 各widgetには独自のビルド関数があり、頻繁に呼び出されます。 この再構築から完了までの間に、パフォーマンスの何パーセントを消費しましょうか? これらすべてに答えられるために、Element Tree, Widget Tree と Render Treeを理解する必要があります。そして、Flutterの build(){…}メソッドを実行する方法、画面上の情報を再構築または変更する方法も理解することも必要です。 本当に何が起こったのでしょうか? Flutterは、build(){…} メソッドが呼び出されるたびに、UI全体を再描画または再作成するわけではありません。 それは、詳しく話しましょう。 Flutterで作成されたアプリケーションのデフォルト構成は60FPS(Frames Per Second)です。 つまり、Flutterシステムは毎秒60回インターフェイスを再描画します。 これは、Flutterが1秒間に60回レイアウト全体を再計算しなければならない場合にのみ、非効率になります。 Flutterが初めて画面に何かを描画する場合、画面上のすべてのコンポーネントの位置、色、テキストなどを計算する必要があります。要するに、最初のインターフェイスを描画する時、Flutterは画面上のそれぞれのピクセルを編集しなければなりません。 次回の編集/描画では、何も変更されていない場合にUIを更新するために、Flutterは既存の古い情報を取得し、画面上に超高速かつ非常に効率的に描画します。 その為に、再描画の速度が問題になく、Flutterが更新のたびに画面上のすべてを再計算する必要がある場合にのみ、問題になります。 では、この記事で、Flutterがbuild(){…}メソッドが呼び出されるたびにすべてを再計算するかどうかという内容を詳細に理解しましょう! Widget Tree‌‌ 簡単に言えば、Widget Tree というのは、アプリケーションの構築に使用されているすべてのWidgetです。つまり、書いたコードからwidget treeが作成されます。 それは完全に管理できます。widgetを宣言して、それらを一緒にネストすることで要望のレイアウトを作成します。 build(){…}メソッドを呼び出す時に、FlutterでWidget Treeがビルドされます。 Flutterシステムは、この部分を独自に処理します。 画面に表示されるだけではありません。 代わりに、Flutterまでに次回画面に何を描画するかと指示します。 Widget treeは頻繁に再構築されます。 Element Tree‌‌ Element Tree はWidget Treeにバインドされ, 実際に表示されているオブジェクト/要素と設定される情報です。再構築することはめったにありません。 Element Tree は別の方法で管理され、build(){…} メソッドが呼び出されても再構築されません。 Widget Treeの各 Widgetで、FlutterはそのWidgetのelementを自動的に作成します。 FlutterがWidgetを初めて処理するとすぐに実行されます。 ここで、elementは、Flutterによってメモリ内で管理されるオブジェクトであると言えます。Widget TreeのWidgetに関連します。 Elementは、ターミナルインターフェイスパラメータがあるWidget(Widget Tree内)への参照を1つだけ保持します。 Render Tree‌‌ Render Tree は、画面に表示されるelement /オブジェクトを表します。 Render Tree も頻繁に再構築されません!

Read More

Flutterの基本:最初のアプリプログラミング(第二部)

第一部はこちら ウィジェットを作成する Flutterアプリのすべてがウィジェットです! したがって、Flutterで画面に表示される全ての要素がウィジェットである。material.dart packageによって提供されるウィジェットには2つのタイプがあり、そのタイプの上で自分のカスタムウィジェットを構築します。それらはStatefulウィジェットとStatelessウィジェットです。 このシリーズの今後の記事では、state、stateful widgets 、およびstateless widgetsについて詳しく説明します。 Flutter and Dartプラグインを設定する場合、IDEまたはエディターで独自のカスタムウィジェットが構築できます。Statelessまたはstatefulを入力するだけで、IDEがそれに応じて提案を行います。 以下の例では、MyAppという名前のstatelessウィジェットを作成します。ウィジェットには任意の名前を選択できます。 この例の通り、独自のカスタムstatelessウィジェットを作成するため、material package によって提供されるStatelessWidgetを拡張しています。@overrideは、material packageによっても提供されるdecoratorです。 ウィジェットはabstract classであり、ビルドメソッドをオーバーライドする必要があります。このメソッドには、Flutterが提供するBuildContextのコンテキストが必要です。このメソッド内で、設立又は表示が必要なウィジェットを返します。 そこで、この例では、Flutterのmaterial.dartパッケージによって提供される組み込みウィジェットでもあるMaterialAppを返します。このウィジェットは、コンストラクターで複数の引数を受け入れます。詳細については、Material App にカーソルを合わせるか、Command+クリック又はCtrl +MaterialAppウィジェットをクリックしてください。 MaterialAppの3つのパラメーター(タイトル、テーマ、ホーム)を定義する必要があります。タイトルは単に文字列を受け入れることです。 値として「First App Demo」を提供します。テーマは、Flutter material packageの組み込み型であるThemeDataデータ型の値が必要です。したがって、次の例のように初期化します。 ThemeDataは、app Default themeを設定するために複数の値を受け入れます。primarySwatchは、MaterialColorタイプの値を受け入れる必須パラメーターです。これも組み込みタイプであり、Flutterがアプリのテーマを構築するためのColors.amberを提供するものです。 次に、ウィジェットタイプを受け入れるようにホームを設定する必要があります。ここで提供したウィジェットが画面に表示されます。そして、次のようなコンテナで初期化します:「home:Container(),」。これはまもなくカスタムウィジェットに置き換えられます。ウィジェットは次のようになります。 Main関数 アプリケーションを実行するには、main関数が必要です。main関数は、(){…}の一般的な構文を使用するか、 ()=>の矢印関数として定義することで記述できます。両方の構文は以下のコードを見て見ましょう。 又は: 上記の両方が正常に実行します。それでも、単一の値を返す必要がある場合は、矢印関数の方が良いと思います。そして、F5またはRun | Debugを押下してアプリケーションを実行すると、空白の画面が表示されます。 Statefulウィジェットを作成する FlutterにはStatelessとStatefulの2種類のウィジェットがあります。そのうち、Statefulウィジェットとは状態を持つウィジェットです。今回はStatefulWidgetを作成する方法を学習しましょう! Statefulウィジェットを作成するには、statefulを入力してTabを押すで、IDE又はEditorのオートコンプリート機能を使用します。例えば、以下のようなDummyWidgetという名前のStatefulウィジェットを作成しています。 StatefulウィジェットはStateless ウィジェットに比べると、違う点があります。 例えば、Statefulウィジェットは内部データの変更に対応し、自体が再レンダリングで変更を反映します。一方、Stateless ウィジェットは自体が再レンダリングしません。そして、この課題については、今後の記事で詳しく説明します。 Statefulウィジェットを理解するには、ある種の内部データが必要です。ここでは、_isGreenという名前のboolean値を使用して、デフォルトでfalseに初期化します。変数の前に_を付けて、Dartでのプライベート変数にし、このクラス内でのみアクセスできるようにしています。 それとともに、Widget build(BuildContext context){…}methodから空のコンテナーを返す代わりに、他の結果を返します!その結果はmaterial packageで提供されるウィジェットであるScaffoldを返すことです。新しい/異なる画面を表示するたびに、Scaffoldを提供する必要があることに注意してください。そして、Scaffoldは、初期化の方法でいくつかのパラメーターを受け入れます。 ここでは、appBarとbodyを提供して、画面にコンテンツをご覧になります。DummyWidgetが次のように表示されます。 このStateful DummyWidgetには、デフォルトがfalseの_isGreenという名前のbool型のprivate変数があります。コンテナを返す代わりに、Scaffoldウィジェットを返ます。そして、appBarとbodyの2つのパラメータを提供しました。

Read More

基本的なフラッター:マルチスクリーンアプリケーションを作成します(第一部)

この記事では、Navigationを使用してFlutterでマルチスクリーンアプリケーションを構築し、routesを通して画面間でデータを渡す方法を調べます。 基本的なFlutterのシリーズのこの記事まで、主に単一画面のアプリを中心に説明してきました。 マルチスクリーンアプリケーションの構築を熱心に待っていれば、この記事が役に立ちます!  アプリケーションにマルチスクリーンを追加して、画面遷移する方法を見ていきます。 また、widget間でデータを渡す方法についても説明します。 このテーマについて詳しく見ていきましょう! App Demoによるガイダンス 以下では、作成するサンプルアプリケーションの概要です: ご存知のとおり、このアプリケーションには2つの画面があり、この画面から別の画面にデータを渡したい場合はどのように構築できるか見てみましょう!  The First Screen(最初の画面) 以下は、このアプリケーションで使用する最初の画面のsnapshot codeです。別のファイル(first_screen.dart)に別のWidgetを書き込み、後でmain.dartファイルにインポートします。これは、コードの量を減らし、メンテナンスを容易にし、パフォーマンスを最適化しできます。 FirstScreenがstateless widgetであることがわかります。 概要では、appBarとBodyセクションを含むScaffoldがあります。 Bodyセクションには、コラムWidget(Widgetがコラムでビューを表示する)があり、コラムの子Widgetは、それぞれSizedBox、Text、およびElevatedButtonです。Raised Buttonをクリックすると、ナビゲーターは2番目の画面を最初の画面の上部に2番目の画面の識別子名(named route)で遷移します。 これについては後でもっと説明します。 ナビゲートしたい画面をFlutterに認識させるために、その画面の名前に通して遷移します。 したがって、この画面を使用することを宣言するところでsecond_screen.dartをインポートする必要があります。 注意:ナビゲートする必要のある各画面(各scaffold widgetは個別の画面として見なされます)には、固有の識別子が必要です。 ここでは、両方の画面でstatic constとしてrouteNameを定義しました。 The second screen (2番目の画面)  別のsecond_screen.dartで宣言された2番目の画面には、次のコードが含まれています。 このWidgetのコード構造は基本的に最初の画面と同じですが、ボタンが1つ追加されます。 ここでは、ナビゲートする必要がある画面をrouteName定数でナビゲートできるように、first_screen.dartをインポートします。 2番目のボタンは TextButtonです。FlatButton がpop()メソッドで最初の画面に遷移するために使用されます。 pop()メソッドは、スタックからWidget/トップ画面を削除するだけです。 これについては、さらに詳しく説明します。 main.darrt ファイル ナビゲーションの設定はまだ完了していません。 また、main.dartファイルには、MaterialAppWidgetにあるすべての画面のルートを登録する必要があります。 main.dartファイルにfirst_screen.dartウィジェットとsecond_screen.dartウィジェットの両方をインポートしたことがわかります。 デフォルトのルートページでは:アプリが起動される時にinitialwidget/screenとしてFirstScreen()を使用しています。 また、アプリケーションの最上位のroutesについて説明したと気付いたこともあります。 マルチスクリーンの場合は、ここですべてのスクーンを登録する必要があります。 上記のようなroutesを宣言する必要がある理由 FlutterでNavigatorの動作は、対応する多くのルートのマップで名前付きルート名(route)を検索するようなものです。 名前が有効な場合、builder(){…}メソッドが連結されます。つまり、WidgetBuilderを使用して、Flutterアプリで画面ナビゲーション操作を実行するMaterialPageRouteを作成します。 route nameにstatic constを使用するのはなぜでしょうか? アプリの外部のrouteテーブルで名前を直接宣言してから、その値を使用して、ナビゲーションすることで、 route

Read More

Flutterの基本:最初のアプリプログラミング(第一部)

Flutterは、モバイルだけでなく、Web、組込システム、デスクトップアプリなどの他のプラットフォームでも開発が益々進んでいます。Flutterを学ぶ時間が現在限りです。! 最初のアプリの作成を開始する事より良いことは何ですか?それでは、すぐに始めましょう! 環境設定 この投稿シリーズでは、EditorとしてVisual Studio Codeを使用しています。どんなeditorでも使用できます。Flutter SDKがPCにインストールされていることを確認しましょう。また、Emulatorまたは任意のAndroidデバイスでアプリを実行出来るようにAndroid Studioをインストールする必要があります。macOSを使用している場合は、iOSシミュレーターまたは実際のiOSデバイスでFlutterアプリを実行するようにXCodeを設定することもできます。 我々のデモアプリ ここでは、Flutterとそのwidgetのいくつかにすばやく慣れるために、デモシングルページアプリケーション(単一画面のアプリ)を構築します。デモアプリは次のようになります、 これは、アプリバーとボタンにテキストを表示するために構築するとても簡単なアプリです。ボタンをクリックすると、背景色が変わります。 アプリの初期化 新しいアプリケーションを初期化するには、terminal/consoleでディレクトリパスを指定し、以下のコマンドを使用します、 または、Android StudioまたはVS Codeコマンドパレットから新しいFlutterプロジェクトを作成することもできます。 プロジェクトフォルダの構造 最初のアプリの作成を開始する前にプロジェクトフォルダの構造をざっと目を通しておきましょう。 フォルダー「android」 このフォルダーには、Androidアプリケーションのすべてのプロジェクトファイルがあります。ここで変更を加えたり、必要な権限とAndroidのネイティブコードを追加したりできます。 フォルダー「build」 このフォルダーには、アプリバンドル、apkファイル、その他の関連ファイルやフォルダーなど、コンパイルされたすべての出力が含まれます。 フォルダー「ios」 このフォルダーには、iOSアプリのすべてのネイティブコードがあります。androidフォルダーと同様に、ここで必要な権限を追加し、iOSのネイティブコードを追加できます。 フォルダー「lib」 libフォルダーに、main.dartファイルがあります。 このフォルダーに記述されているすべてのdartコードは、コンパイル時にネイティブプラットフォームコード(ネイティブAndroidとiOS)にコンパイルされます。 フォルダー「test」 このフォルダーには、Flutterアプリケーションのunit testを記述できます。 ファイル「.gitignore」 プロジェクトのバージョン管理システム(version control)としてGITを使用している場合は、このファイルに精通していると思います。 GITに制御させたくない、変更を追跡させたくないファイルとフォルダーは、このファイルで宣言されます。 ファイル「pubspec.lock」と「pubspec.yaml」 このファイルには、必要なすべてのパッケージ名、それのバージョン、内容へのリンク、ディペンデンシーズ、アプリ名、アプリのバージョン、アプリのディペンデンシーズなどが含まれています。 ファイル「README」 これは、アプリケーションに関するすべての基本情報と記述を含むマークダウンファイルです。 エミュレーター/実際のデバイスでアプリを実行します アプリを実行するには、既存のAndroidエミュレーターまたはiOSエミュレーターを作成または開いてみてましょう。ibフォルダーとmain.dartファイルを開き、F5を押してアプリケーションを実行します。 VSコードエディターにflashingとdartの拡張機能がインストールされている場合は、main.dartファイルのvoid main()関数にマウスオーバーするとRun | Debugオプションが表示されます。  アプリを実行すると、基本的なFlutterアプリが自動的に生成されます。 main.dartファイルは、Flutterアプリケーションのエントリポイントです。 いかなるFlutterアプリケーションの実行は、void main(){…}から始まります。 これから、すべてを削除して、アプリケーションを最初から始めましょう。 アプリケーションをビルドします。 main.dartファイルのコードを削除しました。 次のようにアプリの作成を再開しましょう。 パッケージのインポート まず、必要なパッケージをインポートする必要があります。このアプリケーションでは、Flutterに提供されるmaterialパッケージが必要です。すべてのウィジェットと関数は、このパッケージに基づいて構築されています。 次のコマンドでこのパッケージをインポートできます。 アプリケーションで他のパッケージを追加する必要がある場合、コマンドは上記と同じ、パッケージ名を変更するだけです。 ここまで第一部は終わりです。この記事の第二部でお会いしましょう!

Read More

基本的なFlutter:Dartについて理解する (第二部)

第一部はこちら Objects Dartのすべてがオブジェクトです! nullを含むすべてのオブジェクトは、あるクラスのインスタンスであり、これらのクラスのすべてはオブジェクトクラスから継承します。これを確認するために、isの演算子とis!の演算子を使用して、オブジェクトがインスタンスであるかクラスのタイプであるか確認出来ます。以下の例を見てみましょう。 上記のコードの結果は以下の通りです。 したがって、DartでのすべてがObjectであり、classの名前が識別子データ型 (Data Type Identifier)であることがはっきりとわかります。上記の例での$の演算子はdynamicデータを文字列に入れるために使用されています。マルチレベル値の場合、$ {person.name}または$ {77.99はdouble}のように{}とともに$を使用します。Single valueまたは変数を使用する場合は、「私の名前は$ name」のように、{}なしでプレーンな$を使用できます。ここで、nameは変数です。 Classes(クラス) 他のオブジェクト指向プログラミング言語と同様に、classはDartのコア機能です。Classはオブジェクトの仕様を定義できます。クラスには、UpperCamelCase命名規則に従って名前を付ける必要があります。Classの内で、Objectがどのように表示されるかを定義します。 データ間のより複雑な関係を表現したい場合、または特定の機能を単一のビルディングブロック (one building block)にカプセル化したい場合は、通常、独自のクラスを作成します。 上記のコードの結果は以下の通りです。 2つのinstance変数(class-level)を持つProductという名前のclassがあります。instance変数という意味はいくつかの値で初期化するclass内の変数です。 ここでは、dart type-inferenceのため、varを使用して変数を定義しています。Dartは、var型の変数に割り当てられた値型を自動参照することについて便利です。 次に、main(){…}関数でProduct というclassを使用する2つの新しいObjectsを作成します。objectName.instanceVariableNameのようにドット「.」を使用してclass / instance変数にアクセスできます。例えば、product1.nameです。これらの変数に新しい値を割り当てることもできます。 Dartでprivate変数を宣言するには、_descriptionのようにinstance変数名の前に_を使用します。これにより、変数がprivateになり、class外でアクセスできなくなります。そして、Lists、Maps、const、finalを見てみましょう。 Final とconst Dartであるconstおよびfinalのようなキーワードは、固定値変数を作成するために使用されます。それでは、違い点は何でしょうか? Constはコンパイル時定数(compile-time constant)を提供します。つまり、constはプログラミングのコンパイル中で、constの値を宣言する必要があります。それに対して、finalは実行時定数(runtime constant)であり、プログラムの実行中にその値を割り当てることができることを意味します。 よく理解するために、以下の例を見てみましょう。 上記の例のように、PIの値はコンパイル時に認識されます。しかし、square_7の値はコンパイル時に認識されいなく、実行時に計算されます。これは、final(実行時定数)とconst(コンパイル時定数)の主な違い点です。 Dartのリスト 他のプログラミング言語のArraysと同様に、Dartは、固定数の類似またはdynamicのデータ型の変数のいずれかを保持できるArraysのようなデータ構造を構築するためにリストというclassを提供します。Dartには、リストの作成するための[]の構文もあります。 固定的なリスト 固定長であるリストは、その長さを指定することで宣言できます。例えば: List <dynamic>は、9文字の長さのリストを作成します。リストはジェネリック型であるため、リスト内の要素のデータ型は<>内のキーワードによって確定されます。最初の件では、リストの長さは9で、要素のデータ型はdynamicです。そして、2番目の件では、リストの長さは7で、要素のデータ型はstringです。 動的なリスト(Growable lists) 動的リスト (Growable lists)という意味はList()の初期化方法で引数又は値なしで定義されたリストです。以下の例を見てみましょう。 Maps Python辞書またはJavaScriptのリテラルのobjectに精通している場合、Dartのmapsも同様です。基本的に、mapsはkey-valueのペアのコレクションです。 Dartには、mapの作成に使用されるMap classがあります。Mapには、どんなタイプのkeyとvalueを含めることができます。 次の例を見てみましょう。 ここで、1、2、3、4、5はインデックスではなくkeysです。Printステートメントは、次の結果を出します。 Mapの上の.entriesプロパティからアクセスすることで、mapのアイテムを反復処理できます。 上記はDartに関する知識です。Dartがどのように機能するかをより明確にご理解いただくことを願っています。シリーズの次回の記事でお会いしましょう。

Read More