質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.42%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Q&A

解決済

1回答

845閲覧

Flutterで画面遷移を実装したいが、エラーの表示が出てしまう

kosakana1224

総合スコア1

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

0グッド

0クリップ

投稿2023/04/21 05:18

実現したいこと

ここに実現したいことを箇条書きで書いてください。

  • Drawerの設定をところを押すと設定ページへ画面が遷移するようにしたい

前提

ここに質問の内容を詳しく書いてください。
(例)
Flutterでマップアプリを作っています。
画面遷移ができるようにしたいのですが、うまくいきません。エラー内容を調べては見たのですが、改善策がわからないです。

発生している問題・エラーメッセージ

Navigator operation requested with a context that does not include a Navigator.

該当のソースコード

flutter

1import 'package:flutter/material.dart'; 2import 'package:flutter_map/flutter_map.dart'; 3import 'package:footprint_system/achivement_page.dart'; 4import 'package:footprint_system/setting_page.dart'; 5import 'package:latlong2/latlong.dart'; 6import 'package:geolocator/geolocator.dart'; 7import 'package:geocoding/geocoding.dart'; 8 9void main() { 10 runApp(MapApp());//引数として与えられたウィジェットツリーをレンダリングしてアプリを起動 11} 12 13class MapApp extends StatefulWidget {//Stateとともに記述、状態が変更可能なウィジェット 14 @override 15 _MapAppState createState() => new _MapAppState(); 16} 17 18class Home extends StatefulWidget { 19 @override 20 State<StatefulWidget> createState() { 21 // TODO: implement createState 22 throw UnimplementedError(); 23 } 24} 25 26 27class _MapAppState extends State<MapApp> { 28 final MapController _mapController = MapController();//マップの状態を取得したり、変更することができる 29 String _title = 'FootprintSystem';//アプリのタイトル 30 TextEditingController _searchQueryController = TextEditingController();//TextFieldで入力されたテキストを制御 31 List<Location> _searchResults = [];//検索結果の場所のリストを保持するためのリスト,検索結果を表示するためListView.builderで使用される 32 double lat = 35.681;//地図上の位置:緯度 33 double lng = 139.767;//地図上の位置:経度 34 LatLng? tapLatLng;//ユーザが地図上でタップした場所の緯度と経度を保持する 35 Position? _position;//デバイスの現在の位置を表す 36 List<LatLng> _points = [];//通ってきた道を表現するための位置を格納したリスト 37 var currentPosition;//デバイスの現在位置を表し、APIを使用して定期的に更新される 38 List<Marker> markers = [];//クリックまたはタップした地点を記録するリスト 39 List<CircleMarker> circleMarkers = [];//特定の範囲を示すのに使用するマーカーのリスト 40 41 @override 42 Widget build(BuildContext context) { 43 return MaterialApp( 44 debugShowCheckedModeBanner: false,//右上のdebugマークの表示を削除する 45 title: 'map_app', 46 theme: ThemeData( 47 primarySwatch: Colors.blue, 48 ), 49 routes:{//画面遷移するときのルートを指定しておく 50 '/setting':(context) => SettingScreen(value: 100,), 51 '/achievement':(context) => AchievementScreen(value:100), 52 }, 53 home: Scaffold( 54 appBar: AppBar( 55 title: Text(_title), 56 ), 57 // flutter_map設定 58 body: FlutterMap( 59 mapController: _mapController,//FlutterMapにmapControllerを渡す 60 options: MapOptions(//マップの表示に関する設定 61 center: _position != null 62 ? LatLng(lat, lng) 63 : LatLng(35.681167,139.767052),//初期表示される位置を指定 64 zoom: 14.0,//ズームの初期値 65 maxZoom: 18.0,//ズームの最大値(超えるとスマホだと表示されなくなる) 66 interactiveFlags: InteractiveFlag.all, 67 enableScrollWheel: true, 68 scrollWheelVelocity: 0.005, 69 //地図上でタップされた際に実行されるコールバック関数を指定 70 onTap: (tapPosition, latLng) {//(ユーザーがタップした画面上の座標、タップされた地点の緯度経度) 71 tapLatLng = latLng; 72 cleatePin(tapLatLng!);//!はnullでないことを保証するために使用 73 }), 74 children: [//マップに追加される要素のリスト 75 //背景地図読み込み (OSM) 76 TileLayer( 77 urlTemplate: "https://tile.openstreetmap.jp/{z}/{x}/{y}.png", 78 ), 79 // サークルマーカー設定 80 CircleLayer( 81 circles: circleMarkers, 82 ), 83 // ピンマーカー設定 84 MarkerLayer( 85 markers: markers, 86 ), 87 //通ってきた道の設定 88 PolylineLayer( 89 polylines: [ 90 Polyline( 91 points: _points, 92 strokeWidth: 4.0, 93 color: Colors.blue, 94 ), 95 ], 96 ), 97 ], 98 ), 99 endDrawer: Drawer( 100 child: Column( 101 children: [ 102 Expanded( 103 child: ListView( 104 children: [ 105 Padding( 106 padding: const EdgeInsets.all(8.0),//周囲から8.0の余白で囲む 107 child: TextField(//テキスト入力を受け付けるためのウィジェット 108 controller: _searchQueryController, 109 decoration: InputDecoration( 110 hintText: "場所を入力してください", 111 ), 112 onSubmitted: (query) => _performSearch(query),//入力されたテキストを処理する 113 ), 114 ), 115 ListView.builder( 116 physics: NeverScrollableScrollPhysics(), 117 shrinkWrap: true, 118 itemCount: _searchResults.length, 119 itemBuilder: (context,index){ 120 Location location = _searchResults[index]; 121 return 122 ListTile( 123 title: Text(location.toString()), 124 subtitle: Text('${location.latitude}, ${location.longitude}'), 125 onTap: (){ 126 Navigator.pop(context); 127 }, 128 ); 129 }, 130 ), 131 132 ListTile( 133 leading: Icon(Icons.emoji_events), 134 title: Text('アチーブメント'), 135 onTap: () { 136 // アチーブメント画面に遷移する処理を記述する 137 Navigator.pushNamed(context, '/achievement'); 138 }, 139 ), 140 ListTile( 141 leading: Icon(Icons.settings), 142 title: Text('設定'), 143 onTap: () { 144 Navigator.pushNamed(context, '/setting'); 145 }, 146 ), 147 ], 148 ), 149 ), 150 ], 151 ), 152 153 ), 154 ), 155 ); 156 } 157 158 @override 159 void initState() { 160 super.initState();//StatefulWidgetの初期化 161 initLocation();//現在の位置を取得するための非同期関数 162 } 163 164 Future<void> _performSearch(String query) async { 165 try { 166 List<Location> locations = await locationFromAddress(query);//住所に関する単一の場所についてのみ一つの要素を持つ 167 setState(() {//状態の更新 168 _searchResults = locations; 169 //マップを検索された場所にズームする 170 // マップを検索された場所にズームする 171 if (_searchResults.isNotEmpty) { 172 final location = _searchResults.first; 173 final center = LatLng(location.latitude, location.longitude); 174 _mapController.move(center, 18); 175 } 176 }); 177 } catch (e) { 178 print('Error: $e'); 179 } 180 } 181 182 //現在の位置を取得する 183 Future<void> initLocation() async { 184 LocationPermission permission = await Geolocator.checkPermission();//現在の位置情報を取得できるか許可とる 185 if (permission == LocationPermission.denied) { 186 permission = await Geolocator.requestPermission(); 187 if (permission == LocationPermission.denied) { 188 return Future.error('Location permissions are denied'); 189 } 190 } 191 Position position = await Geolocator.getCurrentPosition( 192 desiredAccuracy: LocationAccuracy.high);//現在位置を取得 193 currentPosition = position; 194 final latitude = position.latitude; 195 final longitude = position.longitude; 196 Geolocator.getPositionStream().listen((position) { 197 setState(() { 198 _position = position; 199 _points.add(LatLng(position.latitude, position.longitude)); 200 initCircleMarker(latitude, longitude);//現在の位置情報に基づいて地図上に表示するマーカが初期化 201 }); 202 }); 203 } 204 /// 地図上でピンを作成し、タップすることでピンを選択 205 void cleatePin(LatLng tapLatLng) { 206 Marker marker = Marker( 207 point: tapLatLng, 208 width: 80, 209 height: 80, 210 builder: (context) => Container( 211 child: IconButton( 212 icon: Icon( 213 Icons.location_on, 214 size: 40, 215 color: Colors.red, 216 ), 217 onPressed: () {//ピンをタップした場合に実行される、新しいマーカに置き換える 218 onTapPinCallBack(tapLatLng); 219 }, 220 ), 221 ), 222 ); 223 markers.add(marker); 224 setState(() {}); 225 } 226 227 Future<void> onTapPinCallBack(LatLng latLng) async { 228 final tapMarker = pinReturn(latLng, pinReturn); 229 markers.add(tapMarker); 230 markers.removeAt(1); 231 setState(() {}); 232 } 233 234 Marker pinReturn(LatLng tapLatLng, void tapPin) { 235 return Marker( 236 point: tapLatLng, 237 width: 80, 238 height: 80, 239 builder: (context) => Container( 240 child: IconButton( 241 icon: Icon( 242 Icons.location_on, 243 size: 20, 244 color: Colors.red, 245 ), 246 onPressed: () { 247 pinReturn(tapLatLng, tapPin); 248 }, 249 ), 250 ), 251 ); 252 } 253 254 void initCircleMarker(double latitude, double longitude) { 255 CircleMarker circleMarler = CircleMarker( 256 color: Colors.indigo.withOpacity(0.9), 257 radius: 10, 258 borderColor: Colors.white.withOpacity(0.9), 259 borderStrokeWidth: 3, 260 point: LatLng(latitude, longitude), 261 ); 262 circleMarkers.add(circleMarler); 263 } 264 265 void pinSizeChange() {} 266}

試したこと

MaterialAppのHome部分を分離すればいいとネットで調べたのですが、どのように書けばいいのか初心者なのもあって実装がわかりません。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

MaterialAppは単独で記述し、homeに書くものを別クラスにしておくやり方にするのが基本の書き方です。

一番簡単なのは、_MapAppStateのbuild内にあるMaterialAppの生成をmain側に持ってくるやり方。

dart

1main() { 2 runApp(MaterialApp( 3 debugShowCheckedModeBanner: false,//右上のdebugマークの表示を削除する 4 title: 'map_app', 5 theme: ThemeData( 6 primarySwatch: Colors.blue, 7 ), 8 routes:{//画面遷移するときのルートを指定しておく 9 '/setting':(context) => SettingScreen(value: 100,), 10 '/achievement':(context) => AchievementScreen(value:100), 11 }, 12 home: (home: MapApp())); 13}

エラーメッセージはcontext内にNavigatorがないよというものですが、これはMaterialApp内で作成しています。

提示されたコードだと_MapAppStateのbuildでMaterialAppを生成しているのでbuildの引数であるcontextにはそれが含まれないという状態になります。

分け方の参考になるのはこちらかな。
https://github.com/flutter/codelabs/blob/main/namer/step_03/lib/main.dart
Flutter codelabsのサンプルです。

お勧めではないですが、別の方法としてはScaffoldをBuilderでラップするという方法もあります。
こうすることでMaterialAppで作られたcontextをBuilder経由で渡すこともできます。

dart

1 home: Builder( 2 builder: (context) { 3 return Scaffold(

投稿2023/04/21 11:30

ta.fu

総合スコア1703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.42%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問