[英]How to implement dynamic scrolling via a navbar in flutter for a single-page web app?
我正在尝试找到一种方法来单击导航栏中的元素并让页面自动向下滚动到该部分。 我的单页网站由一个 SingleChildScrollView 组成,不同的部分(例如关于、服务、联系我们等)作为该滚动视图的子部分。 这个结构写在我的主屏幕 class 中。导航栏在不同的 dart 文件中并生成。 我怎样才能使它们相互链接。 GIF: https://imgur.com/a/pukCfao
主屏幕 class(在 main.dart 中启动)
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
TopSection(),
SizedBox(height: kDefaultPadding * 2),
AboutSection(),
ServiceSection(),
TestimonialSection(),
SizedBox(height: kDefaultPadding),
ContactSection(),
SizedBox(height: 50)
],
),
),
);
}
}
您可以在导航栏中单击元素的部分
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: kDefaultPadding * 2.5),
constraints: BoxConstraints(maxWidth: 1110),
height: 100,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
boxShadow: [kDefaultShadow],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(
menuItems.length,
(index) => buildMenuItem(index),
),
),
);
}
Widget buildMenuItem(int index) => InkWell(
onTap: () {
setState(() {
selectedIndex = index;
});
},
更新:
我通过稍微更改您的代码并为我工作解决了这个问题:)我使用ValueNotifier
和ValueLisenableBuilder
来传输值并使用ValueChanged
来将值传递到菜单小部件外部。 但更好,建议使用一位 state 经理来完成这项工作。 对于开关滚动可以使用GlobalKey
和Scrollable.ensureVisible
。
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));
});
},
),
),
),
),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.