Flutter: Прокрутка к началу после нажатия на статус-бар для выбранной вкладки в нижней навигации

Вопросы и ответы

В Flutter мы можем прокрутить к верхней части после нажатия на статус-бар, передав PrimaryScrollController от корневого Scaffold к ScrollView. Однако в моем приложении есть нижняя навигация с 4 вкладками, каждая из которых содержит ScrollView. Когда я нажимаю на статус-бар, все 4 вкладки прокручиваются вверх, но я хочу, чтобы прокручивалась только текущая выбранная вкладка.

Согласно данной теме, похоже, что нет официального способа сделать это
https://github.com/flutter/flutter/issues/85603#issuecomment-876798161

Есть ли какие-либо обходные пути или альтернативные способы прокрутки только выбранной вкладки к верху после нажатия на статус-бар?

Ответ

Для решения проблемы, когда при нажатии на статус-бар во Flutter все вкладки (табы) в нижней навигации прокручиваются к верху, можно использовать ScrollController для каждой вкладки отдельно. Это позволит прокручивать только ту вкладку, которая активна в данный момент. Вот как это можно реализовать:

  1. Создайте ScrollController для каждой вкладки. В зависимости от того, сколько у вас вкладок, вам нужно создать для каждой вкладки свой контроллер.

  2. Создайте метод для прокрутки текущей вкладки вверх при нажатии на статус-бар.

  3. Используйте 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 для управления видимостью вкладок. Это сохраняет состояние каждой вкладки, что полезно, когда вы переключаетесь между ними.

Таким образом, мы можем обеспечить прокрутку только текущей активной вкладки при нажатии на статус-бар.

Оцените материал
Добавить комментарий

Капча загружается...