Flutterを使用したレスポンシブWebおよびデスクトップ開発
公開: 2022-03-10このチュートリアルは、Flutter自体の紹介ではありません。 Flutterの基本を学ぶのに役立つ簡単な紹介とともに、オンラインで利用できる記事、ビデオ、およびいくつかの本がたくさんあります。 代わりに、次の2つの目的について説明します。
- Flutterの非モバイル開発の現状と、デスクトップまたはラップトップコンピューターのブラウザーでFlutterコードを実行する方法。
- Flutterを使用してレスポンシブアプリを作成する方法。これにより、特にWebフレームワークとしてのパワーをフルディスプレイで確認でき、URLに基づくルーティングに関するメモで終わります。
入りましょう!
フラッターとは何か、なぜそれが重要なのか、何に進化したのか、どこに向かっているのか
FlutterはGoogleの最新のアプリ開発フレームワークです。 Googleは、これを包括的であると想定しています。これにより、すべてのブランドのスマートフォン、タブレット、デスクトップおよびラップトップコンピューターで、ネイティブアプリまたはWebページとして同じコードを実行できるようになります。
これは非常に野心的なプロジェクトですが、Googleはこれまで、特に2つの側面で信じられないほどの成功を収めてきました。AndroidとiOSのネイティブアプリ向けの真にプラットフォームに依存しないフレームワークを作成し、本番環境で使用する準備が整っていることと、印象的なフロントを作成することです。 -互換性のあるFlutterアプリとコードの100%を共有できるエンドWebフレームワーク。
次のセクションでは、アプリの互換性と、現在の非モバイルFlutter開発の状況について説明します。
Flutterを使用した非モバイル開発
Flutterを使用した非モバイル開発は、Google I / O 2019で最初に重要な方法で公開されました。このセクションでは、Flutterを機能させる方法と機能するタイミングについて説明します。
Webおよびデスクトップ開発を有効にする方法
Web開発を有効にするには、最初にFlutterのベータチャネルにアクセスする必要があります。 そのポイントに到達するには2つの方法があります。
- SDKアーカイブから適切な最新のベータバージョンをダウンロードして、Flutterをベータチャネルに直接インストールします。
- すでにFlutterがインストールされている場合は、
$ flutter channel beta
でベータチャネルに切り替えてから、Flutterバージョン(実際にはFlutterインストールフォルダーのgit pull
)を$ flutter upgrade
で更新して切り替え自体を実行します。
その後、これを実行できます:
$ flutter config --enable-web
デスクトップのサポートは、特にLinuxとWindowsのツールが不足しているため、プラグインの開発が特に大きな苦痛であり、それに使用されるAPIが概念実証用であり、製造。 これは、WindowsおよびLinuxのネイティブデスクトップアプリでもサポートされていないリリースビルドに実証済みのdart2jsコンパイラを使用しているWeb開発とは異なります。
注: macOSのサポートはWindowsやLinuxのサポートよりもわずかに優れていますが、それでもWebのサポートほど良くはなく、モバイルプラットフォームの完全なサポートほど良くはありません。
デスクトップ開発のサポートを有効にするには、 beta
チャネルについて前述したのと同じ手順に従って、 master
リリースチャネルに切り替える必要があります。 次に、 <OS_NAME>
をlinux
、 windows
、またはmacos
のいずれかに置き換えて、以下を実行します。
$ flutter config --enable-<OS_NAME>-desktop
この時点で、Flutterツールが私が言っていることを実行していないために説明する次の手順のいずれかに問題がある場合、一般的なトラブルシューティング手順は次のとおりです。
-
flutter doctor
を実行して問題をチェックします。 このFlutterコマンドの副作用は、必要なツールがない場合はダウンロードする必要があることです。 -
flutter upgrade
を実行します。 - オフにしてからもう一度オンにします。 コンピュータを再起動するという古いティア1テクニカルサポートの答えは、Flutterの豊富な機能を十分に楽しむために必要なものかもしれません。
FlutterWebアプリの実行と構築
Flutter Webのサポートはまったく悪くありません。これは、Webの開発のしやすさに反映されています。
これを実行しています…
$ flutter devices
…次のようなエントリをすぐに表示する必要があります。
Web Server • web-server • web-javascript • Flutter Tools
さらに、Chromeブラウザを実行すると、Flutterにもそのエントリが表示されます。 互換性のあるFlutterプロジェクトでFlutter flutter run
と(詳細は後で説明します)、表示される「接続されたデバイス」がWebサーバーのみの場合、Flutterはlocalhost:<RANDOM_PORT>
でWebサーバーを起動します。これにより、Flutterにアクセスできるようになります。任意のブラウザからのWebアプリ。
Chromeをインストールしても表示されない場合は、 CHROME_EXECUTABLE
環境変数をChrome実行可能ファイルへのパスに設定する必要があります。
Flutterデスクトップアプリの実行と構築
Flutterデスクトップサポートを有効にした後、Flutterアプリを開発ワークステーションでflutter run -d <OS_NAME>
を使用してネイティブに実行し、 <OS_NAME>
をデスクトップサポートを有効にするときに使用したのと同じ値に置き換えることができます。 flutter build <OS_NAME>
を使用して、 build
ディレクトリにバイナリをビルドすることもできます。
ただし、そのいずれかを実行する前に、Flutterがプラットフォーム用に構築する必要があるものを含むディレクトリが必要です。 これは、新しいプロジェクトを作成するときに自動的に作成されますが、 flutter create .
。 また、LinuxおよびWindows APIは不安定であるため、Flutterの更新後にアプリが機能しなくなった場合は、これらのプラットフォーム用にAPIを再生成する必要があります。
アプリはいつ互換性がありますか?
FlutterアプリがデスクトップまたはWebで機能するためには、「互換性のあるプロジェクト」である必要があると言ったとき、私はずっと何を意味していましたか? 簡単に言うと、ビルドしようとしているプラットフォームのプラットフォーム固有の実装がないプラグインを使用してはならないということです。
この点をすべての人に完全に明確にし、誤解を避けるために、 Flutterプラグインは、その機能を提供するために必要なプラットフォーム固有のコードを含む特定のFlutterパッケージであることに注意してください。
たとえば、Googleが開発したurl_launcher
パッケージを好きなだけ使用できます(Webがハイパーリンク上に構築されている場合は、必要に応じて使用できます)。
Googleが開発したパッケージの例として、Web開発が不可能になる場合はpath_provider
があります。これは、ファイルを保存するローカルストレージパスを取得するために使用されます。 これは、ちなみにWebアプリには役に立たないパッケージの例であるため、使用できないことは、コードを変更する必要があるという事実を除いて、実際には厄介なことではありません。あなたがそれを使用している場合、それはウェブ上で動作します。
たとえば、Web上のlocalStorage
に依存するshared_preferencesパッケージを使用できます。
デスクトッププラットフォームに関しても同様の警告が当てはまります。デスクトッププラットフォームと互換性のあるプラグインはほとんどありません。これは繰り返し発生するテーマであるため、Flutter for the webで実際に必要な作業よりも、デスクトップ側で行う必要のある作業がはるかに多くなります。
Flutterでレスポンシブレイアウトを作成する
上記で説明したことと簡単にするために、この投稿の残りの部分では、ターゲットプラットフォームはWebであると想定しますが、基本的な概念はデスクトップ開発にも適用されます。
Webをサポートすることには、利点と責任があります。 さまざまな画面サイズをサポートすることを余儀なくされることは欠点のように聞こえるかもしれませんが、Webブラウザーでアプリを実行すると、別々に実行しなくても、さまざまなサイズとアスペクト比の画面でアプリがどのように表示されるかを非常に簡単に確認できることを考慮してください。モバイルデバイスエミュレーター。
それでは、コードについて話しましょう。 アプリをレスポンシブにするにはどうすればよいですか?
この分析を行うには、次の2つの観点があります。
- 「どのウィジェットを使用していますか、またはさまざまなサイズの画面に適応できる、または適応する必要があるウィジェットを使用できますか?」
- 「画面のサイズに関する情報を取得するにはどうすればよいですか。また、UIコードを作成するときにそれを使用するにはどうすればよいですか?」
最初の質問には後で答えます。 後者については、最初に話しましょう。これは非常に簡単に処理でき、問題の中心にあるためです。 これを行うには2つの方法があります。
- 1つの方法は、
MediaQuery
ルートのMediaQueryData
から情報を取得することです。この情報は、Flutterアプリ(MaterialApp/WidgetsApp/CupertinoApp
InheritedWidget
一部)が機能するためにウィジェットツリーに存在する必要があります。これは、次のように取得できます。MediaQuery.of(context)
を使用するその他のInheritedWidget
は、Size
型のsize
プロパティを持ち、したがってdouble
型の2つのwidth
プロパティとheight
プロパティを持ちます。 - もう1つの方法は、
LayoutBuilder
を使用することです。これはビルダーウィジェット(StreamBuilder
やFutureBuilder
と同様)であり、minHeight
、maxHeight
、minWidth
、maxWidth
プロパティを持つBoxConstraints
オブジェクトを(context
とともに)builder
関数に渡します。
これは、 MediaQuery
を使用して制約を取得するDartPadの例であり、そのコードは次のとおりです。
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { @override Widget build(context) => Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( "Width: ${MediaQuery.of(context).size.width}", style: Theme.of(context).textTheme.headline4 ), Text( "Height: ${MediaQuery.of(context).size.height}", style: Theme.of(context).textTheme.headline4 ) ] ) ) ); }
そして、これが同じことのためにLayoutBuilder
を使用しているものです:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { @override Widget build(context) => Scaffold( body: LayoutBuilder( builder: (context, constraints) => Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( "Width: ${constraints.maxWidth}", style: Theme.of(context).textTheme.headline4 ), Text( "Height: ${constraints.maxHeight}", style: Theme.of(context).textTheme.headline4 ) ] ) ) ) ); }
それでは、どのウィジェットが制約に適応できるかを考えてみましょう。
まず、画面のサイズに応じて複数のウィジェットをレイアウトするさまざまな方法について考えてみましょう。
最も簡単に適応できるウィジェットはGridView
です。 実際、 GridView
コンストラクターを使用して構築されたGridView.extent
は、この非常に単純な例でわかるように、レスポンシブにするために関与する必要さえありません。
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { final List elements = [ "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit" ]; @override Widget build(context) => Scaffold( body: GridView.extent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, children: elements.map((el) => Card(child: Center(child: Padding(padding: EdgeInsets.all(8.0), child: Text(el))))).toList() ) ); }
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { final List elements = [ "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit" ]; @override Widget build(context) => Scaffold( body: GridView.extent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, children: elements.map((el) => Card(child: Center(child: Padding(padding: EdgeInsets.all(8.0), child: Text(el))))).toList() ) ); }
maxCrossAxisExtent
を変更することで、さまざまなサイズのコンテンツに対応できます。
この例は主にGridView.extent
コンストラクターの存在を示す目的を果たしましたが、それを行うためのはるかに賢い方法は、 SliverGridDelegateWithMaxCrossAxisExtent
でGridView
を使用することです。この場合、ウィジェットはグリッドに表示されGridView.builder
。この例でわかるように、別のデータ構造から動的に作成されます。
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: MyHomePage() ); } class MyHomePage extends StatelessWidget { final List<String> elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => Scaffold( body: GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ) ); }
さまざまな画面に適応するGridViewの例は、私の個人的なランディングページです。これは、 Cards
が少し複雑で大きいことを除いて、前のサンプルコードと同じように、多数のCards
を備えたGridView
で構成される非常に単純なFlutterWebアプリです。 。
電話用に設計されたアプリに加えることができる非常に簡単な変更は、スペースがあるときにDrawer
を左側の永続的なメニューに置き換えることです。
たとえば、ナビゲーションに使用される次のようなウィジェットのListView
を作成できます。
class Menu extends StatelessWidget { @override Widget build(context) => ListView( children: [ FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_one), title: Text("First Link"), ) ), FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_two), title: Text("Second Link"), ) ) ] ); }
スマートフォンでは、 Drawer
の中にある一般的な使用場所(ハンバーガーメニューとも呼ばれます)。
これに代わる方法は、 BottomNavigationBar
またはTabBarとTabBarView
の組み合わせTabBar
が、どちらの場合も、ドロワーで必要とされるよりも多くの変更を加える必要があるため、ドロワーを使用します。
以前に見たMenu
を含むDrawer
を小さな画面でのみ表示するには、次のスニペットのようなコードを記述し、 MediaQuery.of(context)
を使用して幅を確認し、 Drawer
オブジェクトをScaffold
に渡す場合のみアプリに適していると思われる幅の値よりも小さい値:
Scaffold( appBar: AppBar(/* ... \*/), drawer: MediaQuery.of(context).size.width < 500 ? Drawer( child: Menu(), ) : null, body: /* ... \*/ )
それでは、 Scaffold
のbody
について考えてみましょう。 アプリのメインコンテンツのサンプルとして、以前に作成したGridView
を使用します。これは、混乱を避けるためにContent
という名前の別のウィジェットに保持されます。
class Content extends StatelessWidget { final List elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
class Content extends StatelessWidget { final List elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
より大きな画面では、本文自体が2つのウィジェットを表示するRow
である場合があります。1つは固定幅に制限されているMenu
で、もう1つは画面の残りの部分を埋めるContent
です。
小さい画面では、 body
全体がContent
になります。
すべてをSafeArea
ウィジェットとCenter
ウィジェットでラップします。これは、Flutter Webアプリウィジェットが、特にRow
とColumn
を使用している場合に、表示されている画面領域の外側になってしまうことがあり、 SafeArea
やCenter
で修正されるためです。
これは、 Scaffold
のbody
が次のようになることを意味します。
SafeArea( child:Center( child: MediaQuery.of(context).size.width < 500 ? Content() : Row( children: [ Container( width: 200.0, child: Menu() ), Container( width: MediaQuery.of(context).size.width-200.0, child: Content() ) ] ) ) )
これらすべてをまとめると、次のようになります。
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( home: HomePage() ); } class HomePage extends StatelessWidget { @override Widget build(context) => Scaffold( appBar: AppBar(title: Text("test")), drawer: MediaQuery.of(context).size.width < 500 ? Drawer( child: Menu(), ) : null, body: SafeArea( child:Center( child: MediaQuery.of(context).size.width < 500 ? Content() : Row( children: [ Container( width: 200.0, child: Menu() ), Container( width: MediaQuery.of(context).size.width-200.0, child: Content() ) ] ) ) ) ); } class Menu extends StatelessWidget { @override Widget build(context) => ListView( children: [ FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_one), title: Text("First Link"), ) ), FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_two), title: Text("Second Link"), ) ) ] ); } class Content extends StatelessWidget { final List<String> elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
これは、FlutterのレスポンシブUIの一般的な紹介として必要なもののほとんどです。 そのアプリケーションの多くはアプリの特定のUIに依存し、アプリをレスポンシブにするために何ができるかを正確に特定することは困難であり、好みに応じて多くのアプローチをとることができます。 ただし、ここで、一般的なアプリ要素とUIフローについて考えて、より完全な例をレスポンシブアプリにする方法を見てみましょう。
コンテキストに入れる:アプリをレスポンシブにする
これまでのところ、画面だけがあります。 これを、URLベースのナビゲーションが機能する2画面アプリに拡張しましょう。
レスポンシブログインページの作成
アプリにログインページがある可能性があります。 どうすればそれをレスポンシブにすることができますか?
モバイルデバイスのログイン画面は、通常、互いに非常によく似ています。 利用可能なスペースはそれほど多くありません。 これは通常、ウィジェットの周りにいくつかのPadding
がある単なるColumn
であり、ユーザー名とパスワードを入力するためのTextField
と、ログインするためのボタンが含まれています。したがって、かなり標準的です(ただし、必要に応じて機能しません。 、各TextField
のTextEditingController
)モバイルアプリのログインページは次のようになります。
Scaffold( body: Container( padding: const EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text("Welcome to the app, please log in"), TextField( decoration: InputDecoration( labelText: "username" ) ), TextField( obscureText: true, decoration: InputDecoration( labelText: "password" ) ), RaisedButton( color: Colors.blue, child: Text("Log in", style: TextStyle(color: Colors.white)), onPressed: () {} ) ] ), ), )
モバイルデバイスでは問題ないように見えますが、これらの非常に広いTextField
は、大きな画面は言うまでもなく、タブレットでは耳障りに見え始めます。 ただし、携帯電話は画面サイズが異なるため、固定幅だけを決めることはできず、ある程度の柔軟性を維持する必要があります。
たとえば、実験を通じて、最大幅を500にする必要があることがわかります。まあ、 Container
のconstraints
を500に設定します(前の例では、これでどこに行くのかがわかっていたので、 Padding
の代わりにContainer
を使用しました)そして、私たちは行ってもいいですよね? 実際にはそうではありません。ログインウィジェットが画面の左側に固定されるため、すべてを拡大するよりもさらに悪い場合があります。 したがって、次のようにCenter
ウィジェットでラップします。
Center( child: Container( constraints: BoxConstraints(maxWidth: 500), padding: const EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), child: Column(/* ... \*/) ) )
これはすでに問題ないように見え、 LayoutBuilder
またはMediaQuery.of MediaQuery.of(context).size
のいずれかを使用する必要さえありませんでした。 ただし、これを非常に見栄えよくするために、さらに一歩進んでみましょう。 私の見解では、前景部分が背景から何らかの方法で分離されていると、見栄えが良くなります。 これは、入力ウィジェットを使用してContainer
の背後にあるものに背景色を付け、前景のContainer
を白に保つことで実現できます。 見栄えを少し良くするために、大きなデバイスでContainer
が画面の上下に伸びないようにし、角を丸くして、2つのレイアウト間でアニメーション化された素敵なトランジションを与えましょう。
これらすべてに、背景色を設定し、大きな画面の側面だけでなくContainer
全体にパディングを追加するために、 LayoutBuilder
と外部Container
が必要になりました。 また、パディング量の変更をアニメーション化するには、その外側のContainer
をAnimatedContainer
に変換する必要があります。これには、アニメーションのduration
が必要です。これは、0.5秒に設定されDuration(milliseconds: 500)
コード。
レスポンシブログインページの例を次に示します。
class LoginPage extends StatelessWidget { @override Widget build(context) => Scaffold( body: LayoutBuilder( builder: (context, constraints) { return AnimatedContainer( duration: Duration(milliseconds: 500), color: Colors.lightGreen[200], padding: constraints.maxWidth < 500 ? EdgeInsets.zero : EdgeInsets.all(30.0), child: Center( child: Container( padding: EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), constraints: BoxConstraints( maxWidth: 500, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5.0), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text("Welcome to the app, please log in"), TextField( decoration: InputDecoration( labelText: "username" ) ), TextField( obscureText: true, decoration: InputDecoration( labelText: "password" ) ), RaisedButton( color: Colors.blue, child: Text("Log in", style: TextStyle(color: Colors.white)), onPressed: () { Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => HomePage() ) ); } ) ] ), ), ) ); } ) ); }
ご覧のとおり、 RaisedButton
のonPressed
を、 HomePage
という名前の画面(たとえば、 GridView
とメニューまたはドロワーを使用して以前に作成したビューなど)に移動するコールバックに変更しました。 ただし、ここでは、そのナビゲーション部分に焦点を当てます。
名前付きルート:アプリのナビゲーションを適切なWebアプリのようにする
Webアプリに共通するのは、URLに基づいて画面を変更する機能です。 たとえば、 https://appurl/login
にアクセスすると、 https://appurl/somethingelse
somethingelseとは異なるものが表示されます。 実際、Flutterは名前付きルートをサポートしています。これには2つの目的があります。
- Webアプリでは、前の文で述べたのとまったく同じ機能があります。
- どのアプリでも、アプリのルートを事前に定義して名前を付け、名前を指定するだけでそのルートに移動できます。
これを行うには、 MaterialApp
コンストラクターを次のようなものに変更する必要があります。
MaterialApp( initialRoute: "/login", routes: { "/login": (context) => LoginPage(), "/home": (context) => HomePage() } );
次に、Navigator.push(context、route)とNavigator.pushReplacement(context, route)
(context、route)の代わりに、 Navigator.push(context, route)
Navigator.pushNamed(context, routeName)
とNavigator.pushReplacementNamed(context, routeName)
)を使用して別のルートに切り替えることができます。
これは、この記事の残りの部分で作成した架空のアプリに適用されたものです。 DartPadで実際に動作中の名前付きルートを確認することはできないため、 flutter run
を使用して自分のマシンでこれを試すか、動作中の例を確認する必要があります。
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(context) => MaterialApp( initialRoute: "/login", routes: { "/login": (context) => LoginPage(), "/home": (context) => HomePage() } ); } class LoginPage extends StatelessWidget { @override Widget build(context) => Scaffold( body: LayoutBuilder( builder: (context, constraints) { return AnimatedContainer( duration: Duration(milliseconds: 500), color: Colors.lightGreen[200], padding: constraints.maxWidth < 500 ? EdgeInsets.zero : const EdgeInsets.all(30.0), child: Center( child: Container( padding: const EdgeInsets.symmetric( vertical: 30.0, horizontal: 25.0 ), constraints: BoxConstraints( maxWidth: 500, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(5.0), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text("Welcome to the app, please log in"), TextField( decoration: InputDecoration( labelText: "username" ) ), TextField( obscureText: true, decoration: InputDecoration( labelText: "password" ) ), RaisedButton( color: Colors.blue, child: Text("Log in", style: TextStyle(color: Colors.white)), onPressed: () { Navigator.pushReplacementNamed( context, "/home" ); } ) ] ), ), ) ); } ) ); } class HomePage extends StatelessWidget { @override Widget build(context) => Scaffold( appBar: AppBar(title: Text("test")), drawer: MediaQuery.of(context).size.width < 500 ? Drawer( child: Menu(), ) : null, body: SafeArea( child:Center( child: MediaQuery.of(context).size.width < 500 ? Content() : Row( children: [ Container( width: 200.0, child: Menu() ), Container( width: MediaQuery.of(context).size.width-200.0, child: Content() ) ] ) ) ) ); } class Menu extends StatelessWidget { @override Widget build(context) => ListView( children: [ FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_one), title: Text("First Link"), ) ), FlatButton( onPressed: () {}, child: ListTile( leading: Icon(Icons.looks_two), title: Text("Second Link"), ) ), FlatButton( onPressed: () {Navigator.pushReplacementNamed( context, "/login");}, child: ListTile( leading: Icon(Icons.exit_to_app), title: Text("Log Out"), ) ) ] ); } class Content extends StatelessWidget { final List<String> elements = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "A Million Billion Trillion", "A much, much longer text that will still fit"]; @override Widget build(context) => GridView.builder( itemCount: elements.length, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 130.0, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, ), itemBuilder: (context, i) => Card( child: Center( child: Padding( padding: EdgeInsets.all(8.0), child: Text(elements[i]) ) ) ) ); }
フラッターアドベンチャーで
これにより、大画面、特にWebでFlutterを使用して何ができるかがわかります。 それは素敵なフレームワークであり、非常に使いやすく、その極端なクロスプラットフォームのサポートにより、学習して使い始めることがより重要になります。 だから、先に進んで、WebアプリのFlutterも信頼し始めてください!
その他のリソース
- 「デスクトップシェル」、GitHub
デスクトップ上のFlutterの現在の常に最新の状態 - 「Flutterのデスクトップサポート」、Flutter
完全にサポートされているデスクトッププラットフォームに関する情報 - 「FlutterのWebサポート」、Flutter
ウェブ用のFlutterに関する情報 - 「すべてのサンプル」、Flutter
Flutterサンプルとアプリの厳選されたリスト