В Flutter мы можем прокрутить к верхней части после нажатия на статус-бар, передав PrimaryScrollController
от корневого Scaffold
к ScrollView
. Однако в моем приложении есть нижняя навигация с 4 вкладками, каждая из которых содержит ScrollView. Когда я нажимаю на статус-бар, все 4 вкладки прокручиваются вверх, но я хочу, чтобы прокручивалась только текущая выбранная вкладка.
Согласно данной теме, похоже, что нет официального способа сделать это
https://github.com/flutter/flutter/issues/85603#issuecomment-876798161
Есть ли какие-либо обходные пути или альтернативные способы прокрутки только выбранной вкладки к верху после нажатия на статус-бар?
Ответ
Для решения проблемы, когда при нажатии на статус-бар во Flutter все вкладки (табы) в нижней навигации прокручиваются к верху, можно использовать ScrollController
для каждой вкладки отдельно. Это позволит прокручивать только ту вкладку, которая активна в данный момент. Вот как это можно реализовать:
-
Создайте
ScrollController
для каждой вкладки. В зависимости от того, сколько у вас вкладок, вам нужно создать для каждой вкладки свой контроллер. -
Создайте метод для прокрутки текущей вкладки вверх при нажатии на статус-бар.
- Используйте
NotificationListener
для отслеживания нажатий на статус-бар и вызов метода только для активной вкладки.
Ниже приведен пример, как это может выглядеть:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _selectedIndex = 0;
// Создание контроллеров для каждой вкладки
final List<ScrollController> _scrollControllers = [
ScrollController(),
ScrollController(),
ScrollController(),
ScrollController(),
];
// Метод для прокрутки текущей вкладки
void _scrollToTop() {
_scrollControllers[_selectedIndex].animateTo(
0,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Scroll to Top'),
),
body: IndexedStack(
index: _selectedIndex,
children: List.generate(4, (index) {
return NotificationListener<OverscrollNotification>(
onNotification: (ScrollNotification notification) {
// Если кликнули на статус-бар
if (notification is ScrollUpdateNotification &&
notification.metrics.pixels < 0) {
_scrollToTop();
return true;
}
return false;
},
child: SingleChildScrollView(
controller: _scrollControllers[index],
child: Container(
padding: EdgeInsets.all(16.0),
height: MediaQuery.of(context).size.height * 2,
color: Colors.primaries[index % Colors.primaries.length],
child: Center(child: Text('Tab $index')),
),
),
);
})),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Tab 1'),
BottomNavigationBarItem(icon: Icon(Icons.business), label: 'Tab 2'),
BottomNavigationBarItem(icon: Icon(Icons.school), label: 'Tab 3'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Tab 4'),
],
currentIndex: _selectedIndex,
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
),
);
}
@override
void dispose() {
// Освобождаем контроллеры
for (var controller in _scrollControllers) {
controller.dispose();
}
super.dispose();
}
}
Пояснения к коду:
- У нас есть
ScrollController
для каждой вкладки, хранящийся в списке_scrollControllers
. - Метод
_scrollToTop()
анимирует прокрутку текущей вкладки к верху. - Мы используем
NotificationListener
, чтобы слушать обновления прокрутки. Когда происходит прокрутка вверх (проверка наScrollUpdateNotification
), мы вызываем_scrollToTop()
. - Используем
IndexedStack
для управления видимостью вкладок. Это сохраняет состояние каждой вкладки, что полезно, когда вы переключаетесь между ними.
Таким образом, мы можем обеспечить прокрутку только текущей активной вкладки при нажатии на статус-бар.