親の顔より見たアレを Flutter でやります.
override fun onCreate(savedInstanceState: Bundle?) {
val fragment = MainFragment.newInstance()
supportFragmentManager.beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack(null).commit()
supportFragmentManager.addOnBackStackChangedListener {
if (supportFragmentManager.backStackEntryCount > 0) {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
} else {
supportActionBar?.setDisplayHomeAsUpEnabled(false)
}
}
state_notifier を使ってやっていきます.
切り替える Fragment 相当の View の種類の Enum
enum ViewType {
Main,
Sub,
}
StateNotifier を用意します.
@freezed
abstract class AppViewState with _$AppViewState {
const factory AppViewState({
@Default(ViewType.Main) viewType,
}) = _AppViewState;
}
class AppViewStateNotifier extends StateNotifier<AppViewState> {
AppViewStateNotifier() : super(const AppViewState()) {}
void setViewType(ViewType viewType) {
state = state.copyWith(viewType: viewType);
}
}
以下が Fragament 相当の View を持つ View です. WillPopScope は Activity でいう onBackPressed を実現する View だと思ってください. onWillPop で現在の View が Sub だった場合 MainView に切り替えするようにします. AppBar#leading でも View が Sub だったときは back_arrow をセットするようにして setDisplayHomeAsUpEnabled(true) 相当になるようにします. 今回は View が 2 つなのでこんな感じですが,View が 3 つとかの場合は Map とかにしてよしなにするだけですね.
class AppView extends StatelessWidget {
@override
Widget build(BuildContext context) {
var viewType = context.select<AppViewState, ViewType>(
(state) => state.viewType);
return WillPopScope(
onWillPop: () async {
if (viewType == ViewType.Main) {
Navigator.of(context).pop();
} else {
context
.read<AppViewStateNotifier>()
.setViewType(ViewType.Main);
}
return false;
},
child: Scaffold(
appBar: AppBar(
title: const Text('App'),
leading: viewType == ViewType.Main
? null
: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () {
context
.read<AppViewStateNotifier>()
.setViewType(ViewType.Main);
}),
),
body: Container(
child: viewType == ViewType.Main
? _MainView()
: _SubView(),
),
),
);
}
}
View を Sub に切り替えるときは ViewType.Sub を渡すだけです.
class _MainView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: ListView(
children: <Widget>[
ListTile(
title: Text('Sub'),
onTap: () {
context
.read<AppViewStateNotifier>()
.setViewType(ViewType.Sub);
},
),
],
),
);
}
}
もっといいやりかたありそう.