Search code examples
flutterdartflutter-layoutflutter-animation

How To Scroll To A Specific Widget in Flutter Using SingleChildScrollView


I have a MainScreen and SecondScreen. When the drawer item in the MainScreen clicked. It should move to SecondScreen Container widget. But how to do that?

I have set ScrollController for SecondScreen SingleChildScrollView. but how to move to a certain widget?

  1. Create a method in SecondScreen which scroll to the widget?
  2. What if I have 3rd screen which need same functionality.

SecondScreen.dart

import 'package:flutter/material.dart';
  ScrollController scrollController = ScrollController();
  var containerKey = GlobalKey();
class SecondScreen extends StatefulWidget {

  final Key widgetKey;

  const SecondScreen({Key key, this.widgetKey}) : super(key: key);

  @override
  State<SecondScreen> createState() => _SecondScreenState();
}

class _SecondScreenState extends State<SecondScreen> {

@override
  void initState() {
    // TODO: implement initState
    super.initState();
Scrollable.ensureVisible(
    widget.widgetKey,
    duration: const Duration(milliseconds: 400),
    curve: Curves.easeInOut,
);
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        controller: scrollController,
        child: Column(
          children: [
            Text('hi'),
            Container(
              color: Colors.red,
              height: 1000,
            ),
            Container(
              color: Colors.green,
              height: 1000,
            ),
            Container(
              key: containerKey,
              color: Colors.green,
              height: 1000,
            ),
          ],
        ),
      ),
    );
  }
}

mainscreen.dart

import 'package:flutter/material.dart';
import 'package:stackoverflow_check/scrollcheck/second_screen.dart';

class MainScreen extends StatelessWidget {
  const MainScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      drawer: Drawer(
        child: ListView(
          children: [
            TextButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => SecondScreen(widgetKey: containerKey),
                  ),
                );
                //scrollController.an
              },
              child: Text('click'),
            )
          ],
        ),
      ),
    );
  }
}



Solution

  • Main screen

    class MainScreen extends StatelessWidget {
      const MainScreen({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          drawer: Drawer(
            child: ListView(
              children: [
                TextButton(
                  onPressed: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(
                        builder: (context) => SecondScreen(widgetNum: 2),
                      ),
                    );
                    //scrollController.an
                  },
                  child: Text('click'),
                )
              ],
            ),
          ),
        );
      }
    }
    

    SecondScreen

    class SecondScreen extends StatefulWidget {
      final int widgetNum;
      const SecondScreen({Key? key, required this.widgetNum}) : super(key: key);
    
      @override
      State<SecondScreen> createState() => _SecondScreenState();
    }
    
    class _SecondScreenState extends State<SecondScreen> {
      ScrollController scrollController = ScrollController();
      var containerKey = GlobalKey();
      var container2Key = GlobalKey();
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
      }
    
      @override
      void didChangeDependencies() {
        // TODO: implement didChangeDependencies
        super.didChangeDependencies();
        Future.delayed(Duration(milliseconds: 100), () {
          if (widget.widgetNum == 1) {
            Scrollable.ensureVisible(
              containerKey.currentContext!,
              duration: const Duration(milliseconds: 400),
              curve: Curves.easeInOut,
            );
          } else {
            Scrollable.ensureVisible(
              container2Key.currentContext!,
              duration: const Duration(milliseconds: 400),
              curve: Curves.easeInOut,
            );
          }
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: SingleChildScrollView(
            controller: scrollController,
            child: Column(
              children: [
                Text('hi'),
                Container(
                  color: Colors.red,
                  height: 1000,
                ),
                Container(
                  color: Colors.green,
                  height: 1000,
                ),
                Container(
                  key: containerKey,
                  color: Colors.green,
                  height: 1000,
                ),
                Container(
                  key: container2Key,
                  color: Colors.blue,
                  height: 1000,
                ),
              ],
            ),
          ),
        );
      }
    }