【问题标题】:Flutter web tabbarview scrollcontroller not responding to keyboard scrollingFlutter web tabbarview滚动控制器不响应键盘滚动
【发布时间】:2021-08-17 19:04:11
【问题描述】:
  • 我创建了两个选项卡。
  • 在每个选项卡中,我都有使用滚动条包裹的 SingleChildScrollView。
  • 我不能在两个选项卡中都有主滚动控制器,因为这会引发异常:“滚动控制器附加到多个滚动视图。”
  • 对于 Tab ONE,我使用主滚动控制器,对于 Tab 2,我创建了 Scrollcontroller 并附加了它。
  • 对于带有主滚动控制器的 Tab ONE,我可以通过键盘和拖动滚动条滚动。
  • 但是对于带有非主滚动控制器的 Tab TWO,我只能通过拖动滚动条来滚动。此选项卡不响应键盘向上/向下翻页键。

请检查我下面的代码。指导我如何实现 Tab 2 的键盘滚动。

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,
        ),
      ),
    );
  }
}

【问题讨论】:

    标签: flutter flutter-web flutter-scrollbar


    【解决方案1】:

    您无需创建显式 ScrollController 即可实现此目的。

    一个技巧是在Tab 更改其索引时更改哪个SingleChildScrollView 将使用PrimaryScrollController

    所以,当我们侦听该选项卡已更改为索引 0 时,我们将设置第一个 SingleChildScrolViewprimary 之一。当它变为1时,我们将另一个设置为primary

    首先像这样新建一个State变量,

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

    要监听更改事件,需要将监听器添加到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(),
              ],
            ),
          );
        },
      ),
    );
    

    最后,根据currentIndexprimary: 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,
        ),
      ),
    );
    

    现在,您应该可以用键盘控制这两个选项卡了。

    完整代码here

    【讨论】:

    • 谢谢尼桑。这行得通。我赞成你的回答。等待其他回复。如果没有得到更好的答案,将其标记为已接受的答案。好奇,这是滚动控制器中的错误吗?我应该向flutter报告吗?
    • @AshishKhurange 我不认为这是一个错误。这就是它的实现方式。您也可以创建自己的ScrollControllers,但我认为不同之处在于您必须实现自己的功能来响应键盘事件。这绝对是可能的。只是解决这个问题的更难的途径。这就是我没有写那种方法的原因。
    猜你喜欢
    • 2021-08-19
    • 2011-10-30
    • 2021-09-02
    • 2018-04-30
    • 1970-01-01
    • 2021-07-24
    • 2021-11-15
    • 1970-01-01
    • 2020-11-27
    相关资源
    最近更新 更多