Home > Back-end >  How to implement dynamic scrolling via a navbar in flutter for a single-page web app?
How to implement dynamic scrolling via a navbar in flutter for a single-page web app?

Time:01-30

I'm trying to find a way to click on an element in my navbar and have the page auto-scroll down to that section. My one-page website consists of a SingleChildScrollView with the different sections (e.g. about, services, contact us,..) as children of that scroll view. This structure is written in my HomeScreen class. The NavBar is in a different dart file and gets generated. How can I make it so that these get linked to each other. GIF: navbar

CodePudding user response:

UPDATE:

I solved the problem with a little change in your code and work for me :) I use ValueNotifier and ValueLisenableBuilder for transfer value & use ValueChanged for pass value to outside the menu widget. but better and recommended using one state manager for this work . for switch scroll can using GlobalKey and Scrollable.ensureVisible. enter image description here

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  late ValueNotifier<int> notifier;
  final List<GlobalKey> itemKeys = [
    GlobalKey(),
    GlobalKey(),
    GlobalKey(),
    GlobalKey(),
    GlobalKey()
  ];

  @override
  void initState() {
    notifier = ValueNotifier(0);
    super.initState();
  }

  @override
  void dispose() {
    notifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
          child: ValueListenableBuilder<int>(
        valueListenable: notifier,
        builder: (context, val, widget) {
          return Column(children: [
            Menu(
              valueChanged: (int value) {
                print("$value");
                notifier.value = value;
                notifier.notifyListeners();
                Scrollable.ensureVisible(itemKeys[value].currentContext!,
                    duration: Duration(seconds: 1),
                    // duration for scrolling time
                    alignment: .5,
                    // 0 mean, scroll to the top, 0.5 mean, half
                    curve: Curves.easeInOutCubic);
              },
            ),
            Item(title: "Home", key: itemKeys[0]),
            Item(title: "About", key: itemKeys[1]),
            Item(title: "Services", key: itemKeys[2]),
            Item(title: "Testimonials", key: itemKeys[3]),
            Item(title: "Contact", key: itemKeys[4]),
          ]);
        },
      )),
    );
  }
}

class Item extends StatelessWidget {
  const Item({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 400,
      width: double.infinity,
      color: Colors.deepPurpleAccent,
      child: Text("$title"),
    );
  }
}

class Menu extends StatefulWidget {
  Menu({Key? key, required this.valueChanged}) : super(key: key);
  ValueChanged<int> valueChanged;

  @override
  State<Menu> createState() => _MenuState();
}

class _MenuState extends State<Menu> {
  int selectedIndex = 0;
  int hoverIndex = 0;
  List<String> menuItems = [
    "Home",
    "About",
    "Services",
    "Testimonials",
    "Contact"
  ];

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 70 * 2.5),
      constraints: BoxConstraints(maxWidth: 1110),
      height: 100,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.only(
          topLeft: Radius.circular(10),
          topRight: Radius.circular(10),
        ),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: List.generate(
          menuItems.length,
          (index) => Container(
            color: selectedIndex == index ? Colors.red : Colors.green,
            width: 100,
            height: 100,
            child: InkWell(
              child: Text("${menuItems[index]}"),
              onTap: () {
                setState(() {
                  selectedIndex = index;
                  widget.valueChanged((index));
                });
              },
            ),
          ),
        ),
      ),
    );
  }
}
  • Related