Flutter web tabbarview scrollcontroller не отвечает на прокрутку клавиатуры

  • Я создал две вкладки.
  • На каждой вкладке у меня есть SingleChildScrollView, обернутый полосой прокрутки.
  • У меня не может быть основного контроллера прокрутки на обеих вкладках, потому что это вызывает исключение: «Контроллер прокрутки прикреплен к нескольким представлениям прокрутки».
  • Для Tab ONE я использую основной контроллер прокрутки, для Tab TWO я создал Scrollcontroller и прикрепил его.
  • Для Tab ONE с основным контроллером прокрутки я могу прокручивать как с клавиатуры, так и с помощью полосы прокрутки.
  • Но для вкладки TWO с неосновным контроллером прокрутки мне нужно прокручивать только путем перетаскивания полосы прокрутки. Эта вкладка не реагирует на нажатия клавиш вверх / вниз на клавиатуре.

Пожалуйста, проверьте мой код ниже. Расскажите мне, как использовать прокрутку клавиатуры для вкладки TWO.

      import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TabExample(),
    );
  }
}

class TabExample extends StatefulWidget {
  const TabExample({Key key}) : super(key: key);

  @override
  _TabExampleState createState() => _TabExampleState();
}

class _TabExampleState extends State<TabExample> {
  ScrollController _scrollController;

  @override
  void initState() {
    _scrollController = ScrollController();
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              Tab(icon: Text('Tab ONE')),
              Tab(icon: Text('Tab TWO')),
            ],
          ),
          title: Text('Tabs Demo'),
        ),
        body: TabBarView(
          children: [
            _buildWidgetA(),
            _buildWidgetB(),
          ],
        ),
      ),
    );
  }

  Widget _buildWidgetA() {
    List<Widget> children = [];
    for (int i = 0; i < 20; i++) {
      children.add(
        Padding(
          padding: EdgeInsets.symmetric(vertical: 16),
          child: Container(
            height: 100,
            width: double.infinity,
            color: Colors.black,
          ),
        ),
      );
    }
    return Scrollbar(
      isAlwaysShown: true,
      showTrackOnHover: true,
      child: SingleChildScrollView(
        child: Column(
          children: children,
        ),
      ),
    );
  }

  Widget _buildWidgetB() {
    List<Widget> children = [];
    for (int i = 0; i < 20; i++) {
      children.add(
        Padding(
          padding: EdgeInsets.symmetric(vertical: 16),
          child: Container(
            height: 100,
            width: double.infinity,
            color: Colors.green,
          ),
        ),
      );
    }
    return Scrollbar(
      controller: _scrollController,
      isAlwaysShown: true,
      showTrackOnHover: true,
      child: SingleChildScrollView(
        controller: _scrollController,
        child: Column(
          children: children,
        ),
      ),
    );
  }
}

1 ответ

Вам не нужно создавать явное ScrollController для достижения этой цели.

Один из приемов - изменить, который будет использовать PrimaryScrollController всякий раз, когда Tab меняет свой индекс.

Итак, когда мы слушаем, что эта вкладка изменилась на индекс 0, мы установим, что первая SingleChildScrolViewединственный. Когда он изменится на 1, мы установим другой как primary.

Сначала создайте новую переменную состояния, подобную этой,

      int currentIndex = 0; // This will be the index of tab at a point in time

Чтобы прослушивать событие изменения, вам нужно добавить Listener в TabController.

      DefaultTabController(
  length: 2,
  child: Builder(  // <---- Use a Builder Widget to get the context this this DefaultTabController
    builder: (ctx) {

      // Here we need to use ctx instead of context otherwise it will give null
      final TabController tabController = DefaultTabController.of(ctx);

      tabController.addListener(() {
        if (!tabController.indexIsChanging) {

          // When the tab has changed we are changing our currentIndex to the new index
          setState(() => currentIndex = tabController.index);
        }
      });

      return Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              Tab(icon: Text('Tab ONE')),
              Tab(icon: Text('Tab TWO')),
            ],
          ),
          title: Text('Tabs Demo'),
        ),
        body: TabBarView(
          children: [
            _buildWidgetA(),
            _buildWidgetB(),
          ],
        ),
      );
    },
  ),
);

Наконец, в зависимости от currentIndex набор primary: true для каждого SingleChildScrollView.

Для _buildWidgetA,

      Scrollbar(
  isAlwaysShown: true,
  showTrackOnHover: true,
  child: SingleChildScrollView(
    primary: currentIndex == 0,  // <--- This will be primary if currentIndex = 0
    child: Column(
      children: children,
    ),
  ),
);

Для _buildWidgetB,

      Scrollbar(
  isAlwaysShown: true,
  showTrackOnHover: true,
  child: SingleChildScrollView(
    primary: currentIndex == 1,  // <--- This will be primary if currentIndex = 1
    child: Column(
      children: children,
    ),
  ),
);

Теперь вы должны иметь возможность управлять обеими вкладками с помощью клавиатуры.

Полный код здесь

Другие вопросы по тегам