Flutterのファースト・ステップ2
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfras...
-[[戻る>Flutter]]
--...[[Flutterの5thステップ]]
--Flutterのファースト・ステップ2
--[[Flutterのセカンド・ステップ2]]
--[[Flutterのサード・ステップ2]]
*目次 [#d0705168]
#contents
*概要 [#x79dd04e]
2026年、リブートはFlutterデスクトップ(Windows)で実施
-この選択肢は、単純にAndroid/iOSの準備が難しいケースが多...
-(コレは、一先ず、WebAPIを経由した簡単なCRUD処理の実装と...
-Windowsでは、Android/iOSほど「カスタムURLスキームからの...
*詳細 [#b3a57dbc]
**システム要件 [#e740e7e8]
-Windows 10/11(64bit)
-ストレージ:10GB以上の空き
-RAM:8GB以上推奨
**インストール [#gd3d7a56]
***Flutter SDK [#x75e9ac9]
-flutter.dev から Flutter SDK をダウンロード
-%USERPROFILE%\develop\flutter\ などのパスに解凍
-環境変数 PATH に %USERPROFILE%\develop\flutter\bin を追加
-CMD / PowerShellで確認
flutter --version
dart --version
***Visual Studio [#l16d83af]
-Visual Studio のインストールで「C++によるデスクトップ開...
-「MSVC v143(または最新)」「Windows SDK」コンポーネント...
***VS Code [#b5c05e19]
-VS Codeのインストール
-拡張機能 Flutter(Dart含む)をインストール
**設定 [#r9e5e8d7]
CMD / PowerShellで
***有効化 [#qa8b8e13]
Windowsデスクトップ対応を有効化
flutter config --enable-windows-desktop
***確認 [#e693fbe3]
依存関係の確認
flutter doctor
**開発 [#afe00c72]
CMD / PowerShellで
***作成 [#t4b49c03]
flutter create my_app
***編集 [#ta991b13]
cd my_app
***実行 [#u2c7682a]
flutter run -d windows
***デバッグ [#kea768df]
VS Code上から、
-以下から、デバイスを Windows (desktop) に切り替え。
--右下のステータスバー(No Device)
--若しくはコマンドパレット(Ctrl+Shift+P)→ Flutter: Sele...
-.dart ファイルにブレークポイントを設定
-「デバッグと実行」(Ctrl+Shift+D / Cmd+Shift+D) から「▶」...
*導入 [#s915c677]
-AI活用(https://claude.ai/chat)で、殆どWebを参照せず、...
-先ずは、[[3分割レイアウトのCounter>Reactのファースト・ス...
**ツール類の導入手順 [#h9f89f3f]
[[ココまでの導入手順>#b3a57dbc]]もAIに生成させている。
**レイアウト変更 [#c0f7556b]
以下はプロンプト
-1
以下で生成したコードを修正して3分割のヘッダ、左メニュー...
なお、左メニューのリンクを押下するとメインエリアが画面遷...
flutter create my_app
修正内容を教えてください。
-2~
上記の出力が、全て lib/main.dart にまとめられていたため
ページのファイルは分割したい。
以下は、出力から修正ポイントを抜粋したもの。
***フォルダ構成 [#ae76d40f]
lib/
├── main.dart
├── layout/
│ └── main_layout.dart
└── pages/
├── page_home.dart
├── page_about.dart
└── page_settings.dart
***main・layout [#p1811bf1]
-main.dart
import 'package:flutter/material.dart';
import 'layout/main_layout.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Col...
useMaterial3: true,
),
home: const MainLayout(),
);
}
}
-layout/main_layout.dart
import 'package:flutter/material.dart';
import '../pages/page_home.dart';
import '../pages/page_about.dart';
import '../pages/page_settings.dart';
import '../pages/page_contact.dart';
class MainLayout extends StatefulWidget {
const MainLayout({super.key});
@override
State<MainLayout> createState() => _MainLayoutState();
}
class _MainLayoutState extends State<MainLayout> {
int _selectedIndex = 0;
final List<Map<String, dynamic>> _menuItems = [
{'icon': Icons.home, 'label': 'ホーム'},
{'icon': Icons.info, 'label': '概要'},
{'icon': Icons.settings, 'label': '設定'},
];
final List<Widget> _pages = const [
PageHome(),
PageAbout(),
PageSettings(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.p...
title: const Text(
'My Application',
style: TextStyle(color: Colors.white, fontWeig...
),
actions: [
IconButton(
icon: const Icon(Icons.notifications, color:...
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.account_circle, color...
onPressed: () {},
),
],
),
body: Row(
children: [
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
destinations: _menuItems.map((item) {
return NavigationRailDestination(
icon: Icon(item['icon'] as IconData),
label: Text(item['label'] as String),
);
}).toList(),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: _pages[_selectedIndex],
),
],
),
);
}
}
***pages [#xf1f3342]
ホントは、page_contact.dartもあったが割愛。
-page_home.dart
-page_about.dart
-page_settings.dart
**Counter画面 [#ze2cbf5e]
もともとあったIncrement機能が消失したので、page_counter.d...
既存のIncrement機能が消失したのでCounterとして追加して下...
```
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// TRY THIS: Try running your application with "...
// the application has a purple toolbar. Then, w...
// try changing the seedColor in the colorScheme...
// and then invoke "hot reload" (save your chang...
// reload" button in a Flutter-supported IDE, or...
// the command line to start the app).
//
// Notice that the counter didn't reset back to ...
// state is not lost during the reload. To reset...
// restart instead.
//
// This works for code too, not just values: Mos...
// tested with just a hot reload.
colorScheme: .fromSeed(seedColor: Colors.deepPur...
),
home: const MyHomePage(title: 'Flutter Demo Home P...
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. I...
// that it has a State object (defined below) that con...
// how it looks.
// This class is the configuration for the state. It h...
// case the title) provided by the parent (in this cas...
// used by the build method of the State. Fields in a ...
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framewo...
// changed in this State, which causes it to rerun...
// so that the display can reflect the updated val...
// _counter without calling setState(), then the b...
// called again, and so nothing would appear to ha...
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is calle...
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make ...
// fast, so that you can just rebuild anything that ...
// than having to individually change instances of w...
return Scaffold(
appBar: AppBar(
// TRY THIS: Try changing the color here to a sp...
// Colors.amber, perhaps?) and trigger a hot rel...
// change color while the other colors stay the ...
backgroundColor: Theme.of(context).colorScheme.i...
// Here we take the value from the MyHomePage ob...
// the App.build method, and use it to set our a...
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single ...
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a ...
// arranges them vertically. By default, it si...
// children horizontally, and tries to be as t...
//
// Column has various properties to control ho...
// how it positions its children. Here we use ...
// center the children vertically; the main ax...
// axis because Columns are vertical (the cros...
// horizontal).
//
// TRY THIS: Invoke "debug painting" (choose t...
// action in the IDE, or press "p" in the cons...
// wireframe for each widget.
mainAxisAlignment: .center,
children: [
const Text('You have pushed the button this ...
Text(
'$_counter',
style: Theme.of(context).textTheme.headlin...
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
```
***Layout [#x570320f]
main_layout.dart~
_menuItems と _pages にCounterを追記
***pages [#z65213bb]
page_counter.dart
import 'package:flutter/material.dart';
class PageCounter extends StatefulWidget {
const PageCounter({super.key});
@override
State<PageCounter> createState() => _PageCounterState();
}
class _PageCounterState extends State<PageCounter> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.touch_app, size: 64, color:...
const SizedBox(height: 16),
const Text('ボタンを押した回数:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlin...
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
**ヘッダ、左メニューの切出 [#w247e2ee]
-プロンプト
ヘッダ、左メニューを切り出したい。
ちなみに同様のReactプロジェクトでは、pagesではなくcompon...
import 'package:flutter/material.dart';
import '../pages/page_home.dart';
import '../pages/page_about.dart';
import '../pages/page_settings.dart';
import '../pages/page_counter.dart';
class MainLayout extends StatefulWidget {
const MainLayout({super.key});
@override
State<MainLayout> createState() => _MainLayoutState();
}
class _MainLayoutState extends State<MainLayout> {
int _selectedIndex = 0;
final List<Map<String, dynamic>> _menuItems = [
{'icon': Icons.home, 'label': 'ホーム'},
{'icon': Icons.info, 'label': '概要'},
{'icon': Icons.settings, 'label': '設定'},
{'icon': Icons.touch_app, 'label': 'カウンター'},
];
final List<Widget> _pages = const [
PageHome(),
PageAbout(),
PageSettings(),
PageCounter(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.p...
title: const Text(
'My Application',
style: TextStyle(color: Colors.white, fontWeig...
),
actions: [
IconButton(
icon: const Icon(Icons.notifications, color:...
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.account_circle, color...
onPressed: () {},
),
],
),
body: Row(
children: [
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
destinations: _menuItems.map((item) {
return NavigationRailDestination(
icon: Icon(item['icon'] as IconData),
label: Text(item['label'] as String),
);
}).toList(),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: _pages[_selectedIndex],
),
],
),
);
}
}
-出力(構成)
lib/
├── components/
│ ├── app_header.dart
│ └── side_navigation.dart
├── pages/
│ ├── page_home.dart
│ ├── page_about.dart
│ ├── page_settings.dart
│ └── page_counter.dart
└── layouts/
└── main_layout.dart
***補足的に [#ec05e263]
-プロンプト
「components」「pages」は慣例的ですか?
-出力~
pages → screens、components → widgets、page_home → home_s...
lib/
├── screens/ # ← pages/ の代わり
│ ├── home.dart
│ ├── about.dart
│ ├── settings.dart
│ └── counter.dart
├── widgets/ # ← components/ の代わり
│ ├── app_header.dart
│ └── side_navigation.dart
※ 今回は、「_screens」は付与しない方向性で修正
***ファイル修正 [#dd6e961f]
-main_layout.dart
import 'package:flutter/material.dart';
import '../widgets/app_header.dart';
import '../widgets/side_navigation.dart';
import '../screens/home.dart';
import '../screens/about.dart';
import '../screens/settings.dart';
import '../screens/counter.dart';
class MainLayout extends StatefulWidget {
const MainLayout({super.key});
@override
State<MainLayout> createState() => _MainLayoutState();
}
class _MainLayoutState extends State<MainLayout> {
int _selectedIndex = 0;
final List<Map<String, dynamic>> _menuItems = [
{'icon': Icons.home, 'label': 'ホーム'},
{'icon': Icons.info, 'label': '概要'},
{'icon': Icons.settings, 'label': '設定'},
{'icon': Icons.touch_app, 'label': 'カウンター'},
];
final List<Widget> _pages = const [
ScreenHome(),
ScreenAbout(),
ScreenSettings(),
ScreenCounter(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppHeader(),
body: Row(
children: [
SideNavigation(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
menuItems: _menuItems,
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: _pages[_selectedIndex],
),
],
),
);
}
}
-app_header.dart
import 'package:flutter/material.dart';
class AppHeader extends StatelessWidget implements Prefe...
const AppHeader({super.key});
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Theme.of(context).colorScheme.pri...
title: const Text(
'My Application',
style: TextStyle(color: Colors.white, fontWeight...
),
actions: [
IconButton(
icon: const Icon(Icons.notifications, color: C...
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.account_circle, color: ...
onPressed: () {},
),
],
);
}
@override
Size get preferredSize => const Size.fromHeight(kToolb...
}
-side_navigation.dart
import 'package:flutter/material.dart';
class SideNavigation extends StatelessWidget {
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
final List<Map<String, dynamic>> menuItems;
const SideNavigation({
super.key,
required this.selectedIndex,
required this.onDestinationSelected,
required this.menuItems,
});
@override
Widget build(BuildContext context) {
return NavigationRail(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
labelType: NavigationRailLabelType.all,
destinations: menuItems.map((item) {
return NavigationRailDestination(
icon: Icon(item['icon'] as IconData),
label: Text(item['label'] as String),
);
}).toList(),
);
}
}
*参考 [#bd14ad50]
-Flutterを手動でインストールする~
https://docs.flutter.dev/install/manual
-Flutterをデスクトップアプリ開発におすすめしない話 - izan...
https://izanami.dev/post/47b04883-8ea4-4282-85d9-d684bec4...
-デスクトップアプリ(Windows)の開発にFlutterを使うべき?...
https://www.reddit.com/r/FlutterDev/comments/1c9gwpx/shou...
-デスクトップ開発ならFlutterとElectronの友達は何が違うん...
https://qiita.com/UBinKitte/items/ce0596c18ab9fd1d03c7
-FrontendTemplates/UI/XPlat at develop · OpenTouryoProjec...
https://github.com/OpenTouryoProject/FrontendTemplates/tr...
--https://github.com/OpenTouryoProject/FrontendTemplates/...
--https://github.com/OpenTouryoProject/FrontendTemplates/...
終了行:
「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfras...
-[[戻る>Flutter]]
--...[[Flutterの5thステップ]]
--Flutterのファースト・ステップ2
--[[Flutterのセカンド・ステップ2]]
--[[Flutterのサード・ステップ2]]
*目次 [#d0705168]
#contents
*概要 [#x79dd04e]
2026年、リブートはFlutterデスクトップ(Windows)で実施
-この選択肢は、単純にAndroid/iOSの準備が難しいケースが多...
-(コレは、一先ず、WebAPIを経由した簡単なCRUD処理の実装と...
-Windowsでは、Android/iOSほど「カスタムURLスキームからの...
*詳細 [#b3a57dbc]
**システム要件 [#e740e7e8]
-Windows 10/11(64bit)
-ストレージ:10GB以上の空き
-RAM:8GB以上推奨
**インストール [#gd3d7a56]
***Flutter SDK [#x75e9ac9]
-flutter.dev から Flutter SDK をダウンロード
-%USERPROFILE%\develop\flutter\ などのパスに解凍
-環境変数 PATH に %USERPROFILE%\develop\flutter\bin を追加
-CMD / PowerShellで確認
flutter --version
dart --version
***Visual Studio [#l16d83af]
-Visual Studio のインストールで「C++によるデスクトップ開...
-「MSVC v143(または最新)」「Windows SDK」コンポーネント...
***VS Code [#b5c05e19]
-VS Codeのインストール
-拡張機能 Flutter(Dart含む)をインストール
**設定 [#r9e5e8d7]
CMD / PowerShellで
***有効化 [#qa8b8e13]
Windowsデスクトップ対応を有効化
flutter config --enable-windows-desktop
***確認 [#e693fbe3]
依存関係の確認
flutter doctor
**開発 [#afe00c72]
CMD / PowerShellで
***作成 [#t4b49c03]
flutter create my_app
***編集 [#ta991b13]
cd my_app
***実行 [#u2c7682a]
flutter run -d windows
***デバッグ [#kea768df]
VS Code上から、
-以下から、デバイスを Windows (desktop) に切り替え。
--右下のステータスバー(No Device)
--若しくはコマンドパレット(Ctrl+Shift+P)→ Flutter: Sele...
-.dart ファイルにブレークポイントを設定
-「デバッグと実行」(Ctrl+Shift+D / Cmd+Shift+D) から「▶」...
*導入 [#s915c677]
-AI活用(https://claude.ai/chat)で、殆どWebを参照せず、...
-先ずは、[[3分割レイアウトのCounter>Reactのファースト・ス...
**ツール類の導入手順 [#h9f89f3f]
[[ココまでの導入手順>#b3a57dbc]]もAIに生成させている。
**レイアウト変更 [#c0f7556b]
以下はプロンプト
-1
以下で生成したコードを修正して3分割のヘッダ、左メニュー...
なお、左メニューのリンクを押下するとメインエリアが画面遷...
flutter create my_app
修正内容を教えてください。
-2~
上記の出力が、全て lib/main.dart にまとめられていたため
ページのファイルは分割したい。
以下は、出力から修正ポイントを抜粋したもの。
***フォルダ構成 [#ae76d40f]
lib/
├── main.dart
├── layout/
│ └── main_layout.dart
└── pages/
├── page_home.dart
├── page_about.dart
└── page_settings.dart
***main・layout [#p1811bf1]
-main.dart
import 'package:flutter/material.dart';
import 'layout/main_layout.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Col...
useMaterial3: true,
),
home: const MainLayout(),
);
}
}
-layout/main_layout.dart
import 'package:flutter/material.dart';
import '../pages/page_home.dart';
import '../pages/page_about.dart';
import '../pages/page_settings.dart';
import '../pages/page_contact.dart';
class MainLayout extends StatefulWidget {
const MainLayout({super.key});
@override
State<MainLayout> createState() => _MainLayoutState();
}
class _MainLayoutState extends State<MainLayout> {
int _selectedIndex = 0;
final List<Map<String, dynamic>> _menuItems = [
{'icon': Icons.home, 'label': 'ホーム'},
{'icon': Icons.info, 'label': '概要'},
{'icon': Icons.settings, 'label': '設定'},
];
final List<Widget> _pages = const [
PageHome(),
PageAbout(),
PageSettings(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.p...
title: const Text(
'My Application',
style: TextStyle(color: Colors.white, fontWeig...
),
actions: [
IconButton(
icon: const Icon(Icons.notifications, color:...
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.account_circle, color...
onPressed: () {},
),
],
),
body: Row(
children: [
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
destinations: _menuItems.map((item) {
return NavigationRailDestination(
icon: Icon(item['icon'] as IconData),
label: Text(item['label'] as String),
);
}).toList(),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: _pages[_selectedIndex],
),
],
),
);
}
}
***pages [#xf1f3342]
ホントは、page_contact.dartもあったが割愛。
-page_home.dart
-page_about.dart
-page_settings.dart
**Counter画面 [#ze2cbf5e]
もともとあったIncrement機能が消失したので、page_counter.d...
既存のIncrement機能が消失したのでCounterとして追加して下...
```
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// TRY THIS: Try running your application with "...
// the application has a purple toolbar. Then, w...
// try changing the seedColor in the colorScheme...
// and then invoke "hot reload" (save your chang...
// reload" button in a Flutter-supported IDE, or...
// the command line to start the app).
//
// Notice that the counter didn't reset back to ...
// state is not lost during the reload. To reset...
// restart instead.
//
// This works for code too, not just values: Mos...
// tested with just a hot reload.
colorScheme: .fromSeed(seedColor: Colors.deepPur...
),
home: const MyHomePage(title: 'Flutter Demo Home P...
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. I...
// that it has a State object (defined below) that con...
// how it looks.
// This class is the configuration for the state. It h...
// case the title) provided by the parent (in this cas...
// used by the build method of the State. Fields in a ...
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framewo...
// changed in this State, which causes it to rerun...
// so that the display can reflect the updated val...
// _counter without calling setState(), then the b...
// called again, and so nothing would appear to ha...
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is calle...
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make ...
// fast, so that you can just rebuild anything that ...
// than having to individually change instances of w...
return Scaffold(
appBar: AppBar(
// TRY THIS: Try changing the color here to a sp...
// Colors.amber, perhaps?) and trigger a hot rel...
// change color while the other colors stay the ...
backgroundColor: Theme.of(context).colorScheme.i...
// Here we take the value from the MyHomePage ob...
// the App.build method, and use it to set our a...
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single ...
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a ...
// arranges them vertically. By default, it si...
// children horizontally, and tries to be as t...
//
// Column has various properties to control ho...
// how it positions its children. Here we use ...
// center the children vertically; the main ax...
// axis because Columns are vertical (the cros...
// horizontal).
//
// TRY THIS: Invoke "debug painting" (choose t...
// action in the IDE, or press "p" in the cons...
// wireframe for each widget.
mainAxisAlignment: .center,
children: [
const Text('You have pushed the button this ...
Text(
'$_counter',
style: Theme.of(context).textTheme.headlin...
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
```
***Layout [#x570320f]
main_layout.dart~
_menuItems と _pages にCounterを追記
***pages [#z65213bb]
page_counter.dart
import 'package:flutter/material.dart';
class PageCounter extends StatefulWidget {
const PageCounter({super.key});
@override
State<PageCounter> createState() => _PageCounterState();
}
class _PageCounterState extends State<PageCounter> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.touch_app, size: 64, color:...
const SizedBox(height: 16),
const Text('ボタンを押した回数:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlin...
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
**ヘッダ、左メニューの切出 [#w247e2ee]
-プロンプト
ヘッダ、左メニューを切り出したい。
ちなみに同様のReactプロジェクトでは、pagesではなくcompon...
import 'package:flutter/material.dart';
import '../pages/page_home.dart';
import '../pages/page_about.dart';
import '../pages/page_settings.dart';
import '../pages/page_counter.dart';
class MainLayout extends StatefulWidget {
const MainLayout({super.key});
@override
State<MainLayout> createState() => _MainLayoutState();
}
class _MainLayoutState extends State<MainLayout> {
int _selectedIndex = 0;
final List<Map<String, dynamic>> _menuItems = [
{'icon': Icons.home, 'label': 'ホーム'},
{'icon': Icons.info, 'label': '概要'},
{'icon': Icons.settings, 'label': '設定'},
{'icon': Icons.touch_app, 'label': 'カウンター'},
];
final List<Widget> _pages = const [
PageHome(),
PageAbout(),
PageSettings(),
PageCounter(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.p...
title: const Text(
'My Application',
style: TextStyle(color: Colors.white, fontWeig...
),
actions: [
IconButton(
icon: const Icon(Icons.notifications, color:...
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.account_circle, color...
onPressed: () {},
),
],
),
body: Row(
children: [
NavigationRail(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
destinations: _menuItems.map((item) {
return NavigationRailDestination(
icon: Icon(item['icon'] as IconData),
label: Text(item['label'] as String),
);
}).toList(),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: _pages[_selectedIndex],
),
],
),
);
}
}
-出力(構成)
lib/
├── components/
│ ├── app_header.dart
│ └── side_navigation.dart
├── pages/
│ ├── page_home.dart
│ ├── page_about.dart
│ ├── page_settings.dart
│ └── page_counter.dart
└── layouts/
└── main_layout.dart
***補足的に [#ec05e263]
-プロンプト
「components」「pages」は慣例的ですか?
-出力~
pages → screens、components → widgets、page_home → home_s...
lib/
├── screens/ # ← pages/ の代わり
│ ├── home.dart
│ ├── about.dart
│ ├── settings.dart
│ └── counter.dart
├── widgets/ # ← components/ の代わり
│ ├── app_header.dart
│ └── side_navigation.dart
※ 今回は、「_screens」は付与しない方向性で修正
***ファイル修正 [#dd6e961f]
-main_layout.dart
import 'package:flutter/material.dart';
import '../widgets/app_header.dart';
import '../widgets/side_navigation.dart';
import '../screens/home.dart';
import '../screens/about.dart';
import '../screens/settings.dart';
import '../screens/counter.dart';
class MainLayout extends StatefulWidget {
const MainLayout({super.key});
@override
State<MainLayout> createState() => _MainLayoutState();
}
class _MainLayoutState extends State<MainLayout> {
int _selectedIndex = 0;
final List<Map<String, dynamic>> _menuItems = [
{'icon': Icons.home, 'label': 'ホーム'},
{'icon': Icons.info, 'label': '概要'},
{'icon': Icons.settings, 'label': '設定'},
{'icon': Icons.touch_app, 'label': 'カウンター'},
];
final List<Widget> _pages = const [
ScreenHome(),
ScreenAbout(),
ScreenSettings(),
ScreenCounter(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const AppHeader(),
body: Row(
children: [
SideNavigation(
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
menuItems: _menuItems,
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: _pages[_selectedIndex],
),
],
),
);
}
}
-app_header.dart
import 'package:flutter/material.dart';
class AppHeader extends StatelessWidget implements Prefe...
const AppHeader({super.key});
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: Theme.of(context).colorScheme.pri...
title: const Text(
'My Application',
style: TextStyle(color: Colors.white, fontWeight...
),
actions: [
IconButton(
icon: const Icon(Icons.notifications, color: C...
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.account_circle, color: ...
onPressed: () {},
),
],
);
}
@override
Size get preferredSize => const Size.fromHeight(kToolb...
}
-side_navigation.dart
import 'package:flutter/material.dart';
class SideNavigation extends StatelessWidget {
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
final List<Map<String, dynamic>> menuItems;
const SideNavigation({
super.key,
required this.selectedIndex,
required this.onDestinationSelected,
required this.menuItems,
});
@override
Widget build(BuildContext context) {
return NavigationRail(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
labelType: NavigationRailLabelType.all,
destinations: menuItems.map((item) {
return NavigationRailDestination(
icon: Icon(item['icon'] as IconData),
label: Text(item['label'] as String),
);
}).toList(),
);
}
}
*参考 [#bd14ad50]
-Flutterを手動でインストールする~
https://docs.flutter.dev/install/manual
-Flutterをデスクトップアプリ開発におすすめしない話 - izan...
https://izanami.dev/post/47b04883-8ea4-4282-85d9-d684bec4...
-デスクトップアプリ(Windows)の開発にFlutterを使うべき?...
https://www.reddit.com/r/FlutterDev/comments/1c9gwpx/shou...
-デスクトップ開発ならFlutterとElectronの友達は何が違うん...
https://qiita.com/UBinKitte/items/ce0596c18ab9fd1d03c7
-FrontendTemplates/UI/XPlat at develop · OpenTouryoProjec...
https://github.com/OpenTouryoProject/FrontendTemplates/tr...
--https://github.com/OpenTouryoProject/FrontendTemplates/...
--https://github.com/OpenTouryoProject/FrontendTemplates/...
ページ名: