본문 바로가기

개발하자

Go_router에서 탐색 모음을 사용하는 방법은 무엇입니까? | 펄럭이다

반응형

Go_router에서 탐색 모음을 사용하는 방법은 무엇입니까? | 펄럭이다

현재 라우팅 코드를 리팩터링하는 데 어려움을 겪고 있습니다.

&와 같은 간단한 경로를 이미 얻었지만, 여러 화면이 있는 Bottom Navigation Bar로 라우팅을 수행하려고 할 때 문제가 발생합니다. 나는 , , 와 같이 각각의 경로를 따로 가지고 싶다.

하단 탐색 모음이 나타날 때마다 전체 화면이 변경되지 않도록 하려면 동일한 위젯을 다른 매개 변수와 함께 반환해야 한다는 것을 알게 되었습니다항목을 누르고 대신 화면 자체가 되는 하단 탐색 막대 위의 부분만 업데이트합니다.

나는 꽤 까다로운 해결책을 생각해냈다:

GoRoute(
  path: '/:path',
  builder: (BuildContext context, GoRouterState state) {
    final String path = state.params['path']!;

    if (path == 'signin') {
      return const SignInScreen();
    }

    if (path == 'signup') {
      return const SignUpScreen();
    }

    if (path == 'forgot-password') {
      return const ForgotPasswordScreen();
    }

    // Otherwise it has to be the ScreenWithBottomBar

    final int index = getIndexFromPath(path);

    if (index != -1) {
      return MainScreen(selectedIndex: index);
    }

    return const ErrorScreen();
  }
)

이것은 보기에 별로 좋지 않고 또는 같은 서브루트를 추가하는 것을 불가능하게 만든다.

저는 다음과 같이 이해하기 쉬운 것을 원합니다:

GoRoute(
  path: '/signin',
  builder: (BuildContext context, GoRouterState state) {
    return const SignInScreen();
  }
),
GoRoute(
  path: '/signup',
  builder: (BuildContext context, GoRouterState state) {
    return const SignUpScreen();
  }
),
GoRoute(
  path: '/home',
  builder: (BuildContext context, GoRouterState state) {
    return const ScreenWithNavBar(selectedScreen: 1);
  }
),
GoRoute(
  path: '/events',
  builder: (BuildContext context, GoRouterState state) {
    return const ScreenWithNavBar(selectedScreen: 2);
  },
  routes: <GoRoute>[
    GoRoute(
      path: ':id',
      builder: (BuildContext context, GoRouterState state) {
        return const EventScreen();
      }
    )
  ]
)

그 행동을 달성할 방법이 있나요?




이제 를 사용하여 을 생성할 수 있습니다


설명:

~를 사용할 때 유의해야 할 사항

  1. 각 항목에 소품 지정
  2. 페이지를 바꾸고 페이지를 스택으로 푸시하는 데 사용합니다

따라야 할 코드 구조:


final _parentKey = GlobalKey<NavigatorState>();
final _shellKey = GlobalKey<NavigatorState>();

|_ GoRoute
  |_ parentNavigatorKey = _parentKey   👈 Specify key here
|_ ShellRoute
  |_ GoRoute                            // Needs Bottom Navigation                  
    |_ parentNavigatorKey = _shellKey   
  |_ GoRoute                            // Needs Bottom Navigation
    |_ parentNavigatorKey = _shellKey   
|_ GoRoute                              // Full Screen which doesn't need Bottom Navigation
  |_parentNavigatorKey = _parentKey

코드:

라우터


final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();

final router = GoRouter(
  initialLocation: '/',
  navigatorKey: _rootNavigatorKey,
  routes: [
    ShellRoute(
      navigatorKey: _shellNavigatorKey,
      pageBuilder: (context, state, child) {
        print(state.location);
        return NoTransitionPage(
            child: ScaffoldWithNavBar(
          location: state.location,
          child: child,
        ));
      },
      routes: [
        GoRoute(
          path: '/',
          parentNavigatorKey: _shellNavigatorKey,
          pageBuilder: (context, state) {
            return const NoTransitionPage(
              child: Scaffold(
                body: Center(child: Text("Home")),
              ),
            );
          },
        ),
        GoRoute(
          path: '/discover',
          parentNavigatorKey: _shellNavigatorKey,
          pageBuilder: (context, state) {
            return const NoTransitionPage(
              child: Scaffold(
                body: Center(child: Text("Discover")),
              ),
            );
          },
        ),
        GoRoute(
            parentNavigatorKey: _shellNavigatorKey,
            path: '/shop',
            pageBuilder: (context, state) {
              return const NoTransitionPage(
                child: Scaffold(
                  body: Center(child: Text("Shop")),
                ),
              );
            }),
      ],
    ),
    GoRoute(
      parentNavigatorKey: _rootNavigatorKey,
      path: '/login',
      pageBuilder: (context, state) {
        return NoTransitionPage(
          key: UniqueKey(),
          child: Scaffold(
            appBar: AppBar(),
            body: const Center(
              child: Text("Login"),
            ),
          ),
        );
      },
    ),
  ],
);
하단 탐색 막대
class ScaffoldWithNavBar extends StatefulWidget {
  String location;
  ScaffoldWithNavBar({super.key, required this.child, required this.location});

  final Widget child;

  @override
  State<ScaffoldWithNavBar> createState() => _ScaffoldWithNavBarState();
}

class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
  int _currentIndex = 0;

  static const List<MyCustomBottomNavBarItem> tabs = [
    MyCustomBottomNavBarItem(
      icon: Icon(Icons.home),
      activeIcon: Icon(Icons.home),
      label: 'HOME',
      initialLocation: '/',
    ),
    MyCustomBottomNavBarItem(
      icon: Icon(Icons.explore_outlined),
      activeIcon: Icon(Icons.explore),
      label: 'DISCOVER',
      initialLocation: '/discover',
    ),
    MyCustomBottomNavBarItem(
      icon: Icon(Icons.storefront_outlined),
      activeIcon: Icon(Icons.storefront),
      label: 'SHOP',
      initialLocation: '/shop',
    ),
    MyCustomBottomNavBarItem(
      icon: Icon(Icons.account_circle_outlined),
      activeIcon: Icon(Icons.account_circle),
      label: 'MY',
      initialLocation: '/login',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    const labelStyle = TextStyle(fontFamily: 'Roboto');
    return Scaffold(
      body: SafeArea(child: widget.child),
      bottomNavigationBar: BottomNavigationBar(
        selectedLabelStyle: labelStyle,
        unselectedLabelStyle: labelStyle,
        selectedItemColor: const Color(0xFF434343),
        selectedFontSize: 12,
        unselectedItemColor: const Color(0xFF838383),
        showUnselectedLabels: true,
        type: BottomNavigationBarType.fixed,
        onTap: (int index) {
          _goOtherTab(context, index);
        },
        currentIndex: widget.location == '/'
            ? 0
            : widget.location == '/discover'
                ? 1
                : widget.location == '/shop'
                    ? 2
                    : 3,
        items: tabs,
      ),
    );
  }

  void _goOtherTab(BuildContext context, int index) {
    if (index == _currentIndex) return;
    GoRouter router = GoRouter.of(context);
    String location = tabs[index].initialLocation;

    setState(() {
      _currentIndex = index;
    });
    if (index == 3) {
      context.push('/login');
    } else {
      router.go(location);
    }
  }
}

class MyCustomBottomNavBarItem extends BottomNavigationBarItem {
  final String initialLocation;

  const MyCustomBottomNavBarItem(
      {required this.initialLocation,
      required Widget icon,
      String? label,
      Widget? activeIcon})
      : super(icon: icon, label: label, activeIcon: activeIcon ?? icon);
}

출력:

enter image description here

enter image description here




이것은 앞으로 몇 주 안에 해결하기를 희망하는 go_router에 대한 것입니다. 채널을 고정해 주십시오.




결국 저에게 효과가 있었던 해결책은 다음과 같습니다:

허용되는 값을 지정하는 경로를 만들 수 있었습니다:

GoRoute(
  path: '/:screen(home|discover|notifications|profile)',
  builder: (BuildContext context, GoRouterState state) {
    final String screen = state.params['screen']!;

    return TabScreen(screen: screen);
  }
)

이렇게 하면 경로에 포함된 값(예: '/home' 또는 '/discover')을 TabScreen에 전달하고 TabBar를 다시 로드하지 않고 정확히 동일한 위젯을 표시합니다:

class TabScreen extends StatelessWidget {

  const TabScreen({
    super.key,
    required this.screen
  });

  final String screen;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(child: screen == 'home' ? const HomeScreen() : screen == 'discover' ? const DiscoverScreen() : screen == 'notifications' ? const NotificationsScreen() : ProfileScreen(),
        CustomBottomNavigationBar()
     
      ]
    );
  }
}

반응형