2

Is there a way to navigate from one dart "page" to a specific point in another? This will get me to a given page:

Navigator.of(context).push(
  MaterialPageRoute(builder: (context) => WK3()),
);

But I want to navigate to a specific child or row within that page (which is fairly long, and would otherwise require a lot of scrolling). I am used to working with html, where you just have to indicate a position within a page using a hash tag: #here That should be possible to do in Flutter/Dart, right? [addendum] On the target page I have broken up the rows into widgets:

class WKl extends CardExamplesApp {
  const WKl({super.key});

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [

        Image.asset('images/2wk2l.png',
            fit: BoxFit.fitWidth,
            key: Key('wk_2l')),
        SizedBox(
          width: 210,
          height: 173,
          child: FloatingActionButton(
            heroTag: "btn2l",
            elevation: 0,
            backgroundColor: Colors.blue.withOpacity(0),
            shape: BeveledRectangleBorder(borderRadius: BorderRadius.zero),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => KT()),
              );
            },
          ),
        ),
      ],
    );
  }
}

class WKm extends CEA{
  const WKm({super.key});

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child:

      Image.asset('images/2wk2m.png',
          fit: BoxFit.fitWidth),
    );

  }
}

The rows alternate between being "static" and having buttons leading to the second page. This seemed to be the only way to position the buttons on what was once a very long png image, since the buttons could only take relative positions (located on the screen, not within the long column). By pressing one of these buttons, I can navigate to the second page, and then return to an identified row, but only that row is displayed after returning. Way back:

Navigator.pushNamed(
    context,
    '/wk_2l',
    arguments: {'scrollTo': elementId},
);

I have tried variations with .pop, am exploring ways to identify state, stateful, etc., but... the first page should not change state; the second should only appear when called, then allow a return to the first. The column is preceded by a list:

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


  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SingleChildScrollView(
          child: Column(
          children: [
            WKa(),
            WKl(),
etc.

I had thought I might need to fix the row wickets in the column, so the whole column opens and can be scrolled when we return from the second page, but I couldn't even imagine how that might be done. Eventually, though, I realised I just had to "pop" the second page, and the first would open at the point of departure;

onPressed: () {
   Navigator.pop(context);
},

My mistake was not understanding that, when Flutter says a page is "over" another, it really is "over" it, and navigation isn't like in html, php, old-fashioned subroutines, etc.

user8016440
  • 37
  • 1
  • 7

1 Answers1

1

This is not possible by just using the flutter Navigator. What I would do to tackle that issue is that I would pass an argument which contains the scroll position to the Navigator for example:

Navigator.pushNamed(
    context,
    '/wk3',
    arguments: {'scrollTo': elementId}, // or any other logic like half of the screen or so
);

To read more about Navigator and arguments you can check out the official documentation here. You can also do that for none named routes obviously.

Inside your target widget you could then do the following approach.

  1. Take the argument and parse it to whatever you need.
  2. Depending on your page and your scroll behavior you could use the initState to directly scroll to your desired location. What happens next is a bit dependend on your concrete implementation or where you want to scroll. In certain situations it might be more useful to add a postFrameCallBack for your scrolling instead of doing it in the initState. I'll add it for educational reasons in the snippet below.

Assuming we have a ScrollController of a ListView for example the widget we navigated to knows where we want it to scroll to due to our passed argument. If you use for instance a position value here and we have the ScrollController to do something like this:

controller.position.animateTo(
  widget.args.scrollTo, //make sure it has the correct type
  duration: const Duration(seconds: 1),
  curve: Curves.easeInOut,
);

There are also ways you could scroll to a certain element in a list or a column (like for example the 100th element). Check this question for more information. You can find a slight implentation with a scroll controller below:

 class ScreenArguments {
      final String scrollTo;
      ScreenArguments(this.scrollTo);
    }
    
    class Screen extends StatefulWidget {
      final ScreenArguments args;
    
      Screen(this.args, {Key key}) : super(key: key);
    
      @override
      ScreenState createState() => ScreenState();
    }

    class ScreenState extends State<Screen>  {
    
      @override
      void initState() {
        scrollMeTo = widget.args.scrollTo;
        scrollController = ScrollController();
        
        WidgetsBinding.instance
        .addPostFrameCallback((_) => scrollTo(context)); // this is probably safer than doing scrollTo(context) directly in your initState
enter code here
       // if you do not use addPostFrameCallback you can call scrollTo(context) directly.
       //scrollTo could use scrollControler.animateTo() etc.
  }

I dont have ScrollController / ListView implementation

If thats not the case and you do not have a ScrollController and you want just to scroll to any element on your widget things get a little bit more complicated. In that case I'd recommened you to use flutters Scrollable.ensureVisible. Taken from the documentation it does the following:

Scrolls the scrollables that enclose the given context so as to make the given context visible.

Lets assume you have Column inside a SingleChildScrollView to have a foundation for your scrolling behavior. You would then define a GlobalKey for each section of your widget you would like to scroll to. This key would be the identifier which we pass in as an argument. Assuming we have a GlobalKey in the widget which is called second we could do the following:

Scrollable.ensureVisible(
  GlobalObjectKey(widget.args.scrollTo).currentContext, //this would reference second
  alignment: 0.5, // 
  duration: Duration(seconds: 2),
  curve: Curves.easeInOut); 

You can read more about Scrollable.ensureVisible here.

What approach to take is dependended on your needs and on your implementation.

LOLWTFasdasd asdad
  • 2,625
  • 5
  • 26
  • 39
  • Thanx: I've been looking at "lists" because I used them in another context, and been trying to figure out how to place a ".name ==" line, but the "pushNamed" looks promising (and relatively simple). Will let you know how it works. – user8016440 Feb 15 '23 at 12:33
  • Good luck! Let me know if you need more information / help – LOLWTFasdasd asdad Feb 15 '23 at 12:36
  • @user8016440 - if it helps you feel free to mark the question as solved so that it helps others as well :) – LOLWTFasdasd asdad Feb 16 '23 at 12:15
  • 1
    I went with the lists in combination with: ``` Navigator.push( context, MaterialPageRoute( builder: (context) => WK2(), settings: RouteSettings(name: "ar_6x")), ); Simple, seems to work so far; an alternative had "pushNamed," but that didn't seem to work: There was also something with "keys," but that all just seemed too complicated. – user8016440 Feb 16 '23 at 12:15
  • `Navigator.push( context, MaterialPageRoute( builder: (context) => WK2(), settings: RouteSettings(name: "ar_6x")), )` and `pushNamed` are kind of equivalent in that case. Dont worry about that. – LOLWTFasdasd asdad Feb 16 '23 at 12:20
  • I have been trying variations. What I have is... too long to post here... – user8016440 Feb 23 '23 at 08:21
  • So did it work out in the end? – LOLWTFasdasd asdad Feb 23 '23 at 08:27
  • No (see above). It's funny how things I thought would be complex (writing a small game, for example) turned out to be relatively easy, but simple navigation is... hard. – user8016440 Feb 23 '23 at 10:01