hidable icon indicating copy to clipboard operation
hidable copied to clipboard

Nested navigation hidable not responding

Open zoelounge opened this issue 7 months ago • 5 comments

Hello, thanks for your job. If i have a nested navigation like this

Home Practice(StatefullWidget) -> DetailsPractice(StatefullWidget) Profile

in practice hirable it's ok but in detailPractice not responding .

I use go_router and i have this: final ScrollController _genericsSC = ScrollController()

i pass this _genericsSC into Practice and into DetailsPractice

I have a CustomScrollView into a Practice and into a DetailsPractice

if attach scrollController to CustomScrollView in Practice (and not in DetailsPractice) it's run in Practice and not responding in DetailsPractice: it's Ok

if attach scrollController in CustomScrollView in DetailsPractice (and not in Practice) it's run in DetailsPractice and not responding in Practice: it's Ok

But i don't understand why if i attach scrollController to CustomScrollView in Practice and in DetailsPractice, it's run in Practice and NOT responding in DetailsPractice 🤷🏻‍♂️

How to use in both StatefullWidget?

Thanks so much

zoelounge avatar Nov 20 '23 12:11 zoelounge

Hi, first of all thanks for the issue. I'll take a deep look into issue and I'll respond back as soon as possible.

theiskaa avatar Nov 20 '23 12:11 theiskaa

Hi, News? I tried to handle more Scrollview, but it wasn't a good idea. ;-)

zoelounge avatar Dec 21 '23 07:12 zoelounge

Hello, apologies for the delay. We're currently experiencing a busy period, and we regret any inconvenience caused. We aim to address all open issues over the weekend and hope to provide you with feedback regarding your specific issue.

theiskaa avatar Dec 21 '23 18:12 theiskaa

Hi @zoelounge, i've tested the way you described the issue, and actually couldn't reproduce. Can you share your code in order to make it simple to understand the way you use hidable?

I gonna need the widgets you mentioned and one-level up widget (where actually you display them). And also hidable version. Thanks.

theiskaa avatar Dec 24 '23 16:12 theiskaa

Hi @theiskaa thanks for your replay.

This is my test code, please check it and tell me why do not run correctly:

When i pass ScrollController to RequestView it's ok but if i navigate on AboutView, passing the same scrollController to control hidable, the hidable not run because i have this error: "ScrollController attached to multiple scroll views."

Thanks in advanced ;-)

Code

import 'package:flutter/material.dart';

import 'package:flutter/foundation.dart';
import 'package:go_router/go_router.dart';
import 'package:hidable/hidable.dart';

class AppRouter {
  // ScrollController: for bottomNavBar that i pass into ohter widget to controll the scrool on always page
  final ScrollController scrollController = ScrollController();

  final _rootNavigatorKey = GlobalKey<NavigatorState>();
  final _shellNavigatorHomeKey =
      GlobalKey<NavigatorState>(debugLabel: 'shellHome');
  final _shellNavigatorRequestsKey =
      GlobalKey<NavigatorState>(debugLabel: 'shellRequests');

  late final goRouter = GoRouter(
    initialLocation: '/home',
    navigatorKey: _rootNavigatorKey,
    debugLogDiagnostics: true,
    routes: [
      StatefulShellRoute.indexedStack(
        builder: (context, state, navigationShell) {
          return ScaffoldWithNestedNavigation(
            navigationShell: navigationShell,
            scrollController: scrollController,
          );
        },
        branches: [
//home
          StatefulShellBranch(
            navigatorKey: _shellNavigatorHomeKey,
            routes: [
              GoRoute(
                path: '/home',
                name: 'home',
                pageBuilder: (context, GoRouterState state) => NoTransitionPage(
                  key: state.pageKey,
                  child: const HomeView(
                    label: 'Home',
                  ),
                ),
              ),
            ],
          ),
//requests
          StatefulShellBranch(
            navigatorKey: _shellNavigatorRequestsKey,
            routes: [
              GoRoute(
                  path: '/requests',
                  name: 'requests',
                  pageBuilder: (context, state) => NoTransitionPage(
                        key: state.pageKey,
                        child: RequestView(
                          label: 'Request',
                          scrollController: scrollController,
                        ),
                      ),
                  routes: [
                    GoRoute(
                      // ZOE: La soluzione al problema di non avere la navbar
                      path: 'about',
                      name: 'about',
                      builder: (context, state) {
                        return About(
                          scrollController: scrollController,
                        );
                      },
                    ),
                  ]),
            ],
          ),
        ],
      ),
    ],
  );
}

class ScaffoldWithNestedNavigation extends StatelessWidget {
  const ScaffoldWithNestedNavigation({
    Key? key,
    required this.navigationShell,
    required this.scrollController,
  }) : super(
            key: key ?? const ValueKey<String>('ScaffoldWithNestedNavigation'));

  final StatefulNavigationShell navigationShell;
  final ScrollController scrollController;

  void _goBranch(int index) {
    navigationShell.goBranch(
      index,
      initialLocation: index == navigationShell.currentIndex,
    );
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      return ScaffoldWithNavigationBar(
          body: navigationShell,
          selectedIndex: navigationShell.currentIndex,
          onDestinationSelected: _goBranch,
          scrollController: scrollController,
          navigationShell: navigationShell);
    });
  }
}

class ScaffoldWithNavigationBar extends StatelessWidget {
  const ScaffoldWithNavigationBar({
    super.key,
    required this.body,
    required this.selectedIndex,
    required this.onDestinationSelected,
    required this.scrollController,
    required this.navigationShell,
  });
  final Widget body;
  final int selectedIndex;
  final ValueChanged<int> onDestinationSelected;
  final ScrollController scrollController;
  final StatefulNavigationShell navigationShell;

  void _onItemTapped(int index) {
    onDestinationSelected(index);
  }

  void animateScrollOnTop(ScrollController controller) {
    controller.animateTo(
      0.0,
      curve: Curves.easeOut,
      duration: const Duration(milliseconds: 300),
    );
  }

  @override
  Widget build(BuildContext context) {
    if (kDebugMode) {
      final location = GoRouterState.of(context).uri.toString();
      print('goRouter Location $location');
    }
    return Scaffold(
      resizeToAvoidBottomInset: true,
      body: body,
      bottomNavigationBar: SafeArea(
        child: Hidable(
          controller: scrollController,
          child: BottomNavigationBar(
            selectedFontSize: 12,
            unselectedFontSize: 10,
            selectedLabelStyle: const TextStyle(
              color: Colors.black,
              fontFamily: 'Outfit',
              fontWeight: FontWeight.w400,
            ),
            unselectedLabelStyle: const TextStyle(
              color: Colors.green,
              fontFamily: 'Outfit',
              fontWeight: FontWeight.w400,
            ),
            mouseCursor: SystemMouseCursors.grab,
            type: BottomNavigationBarType.fixed,
            backgroundColor: Colors.white,
            currentIndex: selectedIndex,
            elevation: 0,
            showUnselectedLabels: true,
            unselectedItemColor: Colors.blue,
            selectedItemColor: Colors.orange,
            onTap: (index) {
              _onItemTapped(index);
            },
            items: const [
              BottomNavigationBarItem(
                icon: Icon(
                  Icons.home,
                ),
                label: "Home",
                activeIcon: Icon(
                  Icons.home,
                ),
              ),
              BottomNavigationBarItem(
                icon: Icon(
                  Icons.question_answer,
                ),
                label: "Richieste",
                activeIcon: Icon(
                  Icons.question_answer,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

////////////////////////////////// The Home View screen
class HomeView extends StatefulWidget {
  const HomeView({
    super.key,
    required this.label,
  });

  /// The label to display in the center of the screen.
  final String label;

  @override
  State<StatefulWidget> createState() => HomeViewState();
}

class HomeViewState extends State<HomeView> {
  int _counter = 0;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HomeView Screen - ${widget.label}'),
      ),
      body: Center(
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Text('Details for ${widget.label} - Counter: $_counter',
                  style: Theme.of(context).textTheme.titleLarge),
              const Padding(
                padding: EdgeInsets.all(4),
              ),
              TextButton(
                onPressed: () {
                  setState(() {
                    _counter++;
                  });
                },
                child: const Text('Increment counter'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

////////////////////////////////// The RequestView screen
class RequestView extends StatefulWidget {
  final ScrollController scrollController;

  const RequestView({
    super.key,
    required this.label,
    required this.scrollController,
  });

  final String label;

  @override
  State<StatefulWidget> createState() => RequestViewState();
}

class RequestViewState extends State<RequestView> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    widget.scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: GlobalKey(debugLabel: 'RequestViewKey'),
      appBar: AppBar(
        title: Text('RequestView Screen - ${widget.label}'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: CustomScrollView(
          controller: widget.scrollController,
          slivers: [
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => GestureDetector(
                  onTap: () {
                    context.goNamed("about");
                  },
                  child: Text("ELement = ${index + 1}"),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

////////////////////////////////// The AboutView screen
class About extends StatefulWidget {
  final ScrollController scrollController;

  const About({
    super.key,
    required this.scrollController,
  });

  @override
  State<About> createState() => _AboutState();
}

class _AboutState extends State<About> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    widget.scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: GlobalKey(debugLabel: 'AboutViewKey'),
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: const Text(
          'AboutView Screen',
          style: TextStyle(color: Colors.redAccent),
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: CustomScrollView(
          controller: widget
              .scrollController, // here i have the error: "ScrollController attached to multiple scroll views."
          slivers: [
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (context, index) => GestureDetector(
                  onTap: () {
                    context.goNamed("about");
                  },
                  child: Text(
                    "ELement = ${index + 1}",
                    style: const TextStyle(color: Colors.redAccent),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////

final goRouter = AppRouter().goRouter;

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
        routerConfig: goRouter,
        debugShowCheckedModeBanner: false,
        themeMode: ThemeMode.light);
  }
}

zoelounge avatar Jan 18 '24 10:01 zoelounge