statedAt,endedAt,eventUrlなど一部のフィールドが取得できていなくてnullが渡っているので、遷移時にエラーが出るようです。
その箇所を適当に書き換えて動くようにしたら、とりあえず動くので、
ページ遷移時のデータの渡し方自体はこれで良いと思います。
上記フィールドが取得できていないのはfreezedの使い方に原因があるような気がします。
//body.dart
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_connpass_api_app/model/connpass_response.dart';
import 'package:flutter_connpass_api_app/model/event_response.dart';
import 'package:flutter_connpass_api_app/view/main_view_model.dart';
import 'package:flutter_connpass_api_app/view/main_view_model_data.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// AppBarに検索バーを作成
final TextEditingController _search = TextEditingController();
ScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
// Linstenerを追加して更新処理を実装する
_scrollController.addListener(() {
final maxScrollExtent = _scrollController.position.maxScrollExtent;
final currentPosition = _scrollController.position.pixels;
if (maxScrollExtent > 0 && (maxScrollExtent - 20.0) <= currentPosition) {
// ↑ 下端位置から20pixelの位置に達したら、コンテンツを読み込む
// position.maxScrollExtent => ListView全体の下端位置
// position.pixels => 現在の表示位置
}
});
}
/// ListView部分
@override
Widget build(BuildContext context) {
// StateNotifierのStateを読む
// context.select<Data,T>でデータを読み出す
// selectはデータに変化があった際に自動でrebuildしてくれる(copyWith)
final response = context
.select<MainViewModelData, ConnpassResponse>((data) => data.response);
final state = context.select<MainViewModelData, MainViewModelState>(
(data) => data.viewModelState);
final List<EventResponse> eventList =
response != null ? response.events : [];
print("????$eventList");
// ListViewでJSONデータを表示
Widget body = eventList.isNotEmpty
//Widget body = eventList.length > 0
//var body = eventList.isNotEmpty
? ListView(
scrollDirection: Axis.vertical,
controller: _scrollController,
shrinkWrap: true,
children: eventList.map((event) {
print("${event.startedAt}");
return Card(
child: ListTile(
title: Text(event.title),
onTap: () {
Navigator.pushNamed(
context,
'/detail',
//arguments: eventList,
//遷移先はDetailページなので、eventListを渡すのではなく、
// eventを渡す方が自然な気がする。
arguments: event,
);
},
),
);
}).toList())
// bodyの初期画面
: const Center(
child: Padding(
padding: EdgeInsets.all(24),
child: Text(
'ここに検索結果を表示する',
style: TextStyle(fontSize: 19),
textAlign: TextAlign.center,
),
),
);
if (state == MainViewModelState.loading) {
body = const Center(
child: CircularProgressIndicator(),
);
} else if (state == MainViewModelState.error) {
body = const Center(
child: Padding(
padding: EdgeInsets.all(24),
child: Text(
'エラーが発生しました。検索ワードを変えてお試しください',
style: TextStyle(fontSize: 19),
textAlign: TextAlign.center,
),
),
);
}
/// AppBar 検索バー
return Scaffold(
appBar: AppBar(
title: TextField(
controller: _search,
style: const TextStyle(
color: Colors.white,
),
decoration: const InputDecoration(
labelText: '検索バー',
labelStyle: TextStyle(
color: Colors.white,
),
hintStyle: TextStyle(
color: Colors.white,
),
)),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
context.read<MainViewModel>().fetch(_search.text);
})
],
),
body: body,
);
}
}
//detail.dart
import 'package:flutter/material.dart';
import 'package:flutter_connpass_api_app/model/event_response.dart';
import 'package:flutter/gestures.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:url_launcher/url_launcher.dart';
/// イベント詳細のレイアウト
class Detail extends StatelessWidget {
//Detail(EventResponse event);
//const Detail(Type eventResponse, this.event);
//Detail({Key key, @required this.event}) : super(key: key);
@override
Widget build(BuildContext context) {
// パラメーターを取り出す
final EventResponse args = ModalRoute.of(context).settings.arguments;
print("${args.place}"); //変数受け取り確認
print("${args.startedAt}");
print("${args.address}");
return Scaffold(
appBar: AppBar(
title: const Text('イベント詳細'),
),
body: Container(
margin: const EdgeInsets.fromLTRB(10, 20, 30, 40),
padding: const EdgeInsets.fromLTRB(10, 20, 50, 80),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
buildDetail(args),
buildUrl(args),
],
),
),
);
}
Widget buildDetail(EventResponse args) {
Map<String, String> argsDetail = {
//↓'開催日時'、'終了日時'のコメント外すと遷移時にエラー。
//args.startedAtなどがnullなのでエラーが出ていると思われる
//多分freezedの使い方が正しくないので一部のフィールドが取得できずに
//nullになっているのではないかと思われる。
//'開催日時': changeTimeFormat(args.startedAt),
//'終了日時': changeTimeFormat(args.endedAt),
'会場': args.place,
'会場の所在地': args.address,
};
//↓eventは使う必要は無い。
/*
Map<String, String> argsDetail = {
'開催日時': changeTimeFormat(event.startedAt),
'終了日時': changeTimeFormat(event.endedAt),
'会場': event.place,
'会場の所在地': event.address,
};
*/
return Container(
child: buildDetailRow(argsDetail)
);
}
Widget buildDetailRow(Map<String, String> argsDetail) {
final detailList = <Widget>[];
argsDetail.forEach((key, value) {
detailList.add(Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 5, 5, 5),
child: Text(key ?? ''),
),
),
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
//child: Text(key ?? ''),
child: Text(value ?? ''),
),
),
],
));
});
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: detailList,
);
}
Widget buildUrl(EventResponse args) {
return Container(
padding: const EdgeInsets.fromLTRB(10, 15, 0, 0),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
children: [
TextSpan(
text: 'connpassページはこちらから',
style: const TextStyle(color: Colors.lightBlue),
recognizer: TapGestureRecognizer()
..onTap = () async {
await launch(
//args.eventUrlも取得できていないのでnullになっていると思われる。
//args.eventUrl,
'https://rakus.connpass.com/event/204540/',
forceWebView: true, // ios内かブラウザのどちらで開くかを指定 trunはios
forceSafariVC: true, // Android内かブラウザのどちらで開くかを指定 trunはAndroid
);
}
)
],
),
),
);
}
// ISO-8601形式を「○○/○○/○○/○○:○○」に変換
String changeTimeFormat(String before) {
initializeDateFormatting('ja_JP');
final datetime = DateTime.parse(before);
final formatter = DateFormat('yyyy/MM/dd HH:mm');
final formatted = formatter.format(datetime);
return formatted;
}
}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/03/13 17:19 編集
2021/03/14 02:15
2021/03/17 09:23 編集