親の顔より見たアレを 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);
            },
          ),
        ],
      ),
    );
  }
}

もっといいやりかたありそう.