【问题标题】:Flutter web tabbar scroll issue with non primary scrollcontrollerFlutter web tabbar滚动问题与非主滚动控制器
【发布时间】:2021-08-19 16:54:27
【问题描述】:

继续question

上面提供的解决方案很好。但我很难在我的项目中实施。

预期结果:

  • 我创建了两个选项卡。
  • 在每个选项卡中,我都有使用滚动条包裹的 SingleChildScrollView。
  • 我不能在两个选项卡中都有主滚动控制器,因为这会引发异常:“滚动控制器附加到多个滚动视图。”
  • 对于 Tab ONE,我使用主滚动控制器,对于 Tab 2,我创建了 Scrollcontroller 并附加了它。
  • 两个选项卡中的小部件都应该可以使用键盘和鼠标滚动。

实际结果:

  • 对于带有主滚动控制器的 Tab ONE,我可以通过键盘和拖动滚动条滚动。
  • 但是对于带有非主滚动控制器的 Tab TWO,我只能通过拖动滚动条来滚动。此选项卡不响应键盘向上/向下翻页键。
  • 当在选项卡 2 中使用键盘键时,实际上选项卡 ONE 的内容会滚动。

校验码:

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> {

  @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: [
            WidgetC(),
            WidgetD(),
          ],
        ),
      ),
    );
  }
}

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

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

class _WidgetCState extends State<WidgetC>
    with AutomaticKeepAliveClientMixin<WidgetC> {
  List<Widget> children;
  @override
  void initState() {
    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.blue,
            child: Center(child: Text('$i')),
          ),
        ),
      );
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scrollbar(
      key: PageStorageKey('WidgetC'),
      isAlwaysShown: true,
      showTrackOnHover: true,
      child: SingleChildScrollView(
        child: Column(
          children: children,
        ),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

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

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

class _WidgetDState extends State<WidgetD>
    with AutomaticKeepAliveClientMixin<WidgetD> {
  List<Widget> children;
  ScrollController _scrollController;

  @override
  void initState() {
    _scrollController = ScrollController();
    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,
            child: Center(child: Text('$i')),
          ),
        ),
      );
    }
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Scrollbar(
      key: PageStorageKey('WidgetD'),
      isAlwaysShown: true,
      showTrackOnHover: true,
      controller: _scrollController,
      child: SingleChildScrollView(
        controller: _scrollController,
        child: Column(
          children: children,
        ),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

【问题讨论】:

    标签: flutter flutter-web


    【解决方案1】:

    这已被接受为颤振中的错误。 请在此处关注进度:https://github.com/flutter/flutter/issues/83711

    注意其他面临相同问题的开发人员。 为了克服上述问题,我改变了我的设计布局。我使用的是 Navigationrail 小部件,而不是标签栏视图。这解决了我的问题。 NavigationRail 小部件允许我将主滚动控制器附加到多个小部件而不给我例外:“滚动控制器附加到多个滚动视图。” 示例代码。

    import 'dart:math';
    
    import 'package:flutter/material.dart';
    
    void main() => runApp(const MyApp());
    
    /// This is the main application widget.
    class MyApp extends StatelessWidget {
      const MyApp({Key key}) : super(key: key);
    
      static const String _title = 'Flutter Code Sample';
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          title: _title,
          home: MyStatefulWidget(),
        );
      }
    }
    
    /// This is the stateful widget that the main application instantiates.
    class MyStatefulWidget extends StatefulWidget {
      const MyStatefulWidget({Key key}) : super(key: key);
    
      @override
      State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
    }
    
    /// This is the private State class that goes with MyStatefulWidget.
    class _MyStatefulWidgetState extends State<MyStatefulWidget> {
      int _selectedIndex = 0;
      WidgetC _widgetC = WidgetC();
      WidgetD _widgetD = WidgetD();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text('NavigationRail Demo'), centerTitle: true),
          body: Row(
            children: <Widget>[
              NavigationRail(
                elevation: 8.0,
                selectedIndex: _selectedIndex,
                onDestinationSelected: (int index) {
                  setState(() {
                    _selectedIndex = index;
                  });
                },
                labelType: NavigationRailLabelType.all,
                groupAlignment: 0.0,
                destinations: const <NavigationRailDestination>[
                  NavigationRailDestination(
                    icon: Icon(Icons.favorite_border),
                    selectedIcon: Icon(Icons.favorite),
                    label: Text('Tab ONE'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.bookmark_border),
                    selectedIcon: Icon(Icons.book),
                    label: Text('Tab TWO'),
                  ),
                ],
              ),
              const VerticalDivider(thickness: 1, width: 1),
              // This is the main content.
              Expanded(
                child: _getPageAtIndex(_selectedIndex),
              )
            ],
          ),
        );
      }
    
      Widget _getPageAtIndex(int index) {
        switch (index) {
          case 0:
            return _widgetC;
          case 1:
            return _widgetD;
        }
        return Container();
      }
    }
    
    class WidgetC extends StatefulWidget {
      const WidgetC({Key key}) : super(key: key);
    
      @override
      _WidgetCState createState() => _WidgetCState();
    }
    
    class _WidgetCState extends State<WidgetC>
        with AutomaticKeepAliveClientMixin<WidgetC> {
      List<Widget> children;
      @override
      void initState() {
        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.primaries[Random().nextInt(Colors.primaries.length)],
                child: Center(child: Text('$i')),
              ),
            ),
          );
        }
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return Scrollbar(
          key: PageStorageKey('WidgetC'),
          isAlwaysShown: true,
          showTrackOnHover: true,
          child: SingleChildScrollView(
            child: Column(
              children: children,
            ),
          ),
        );
      }
    
      @override
      bool get wantKeepAlive => true;
    }
    
    class WidgetD extends StatefulWidget {
      const WidgetD({Key key}) : super(key: key);
    
      @override
      _WidgetDState createState() => _WidgetDState();
    }
    
    class _WidgetDState extends State<WidgetD>
        with AutomaticKeepAliveClientMixin<WidgetD> {
      List<Widget> children;
    //  ScrollController _scrollController;
    
      @override
      void initState() {
    //    _scrollController = ScrollController();
        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.primaries[Random().nextInt(Colors.primaries.length)],
                child: Center(child: Text('$i')),
              ),
            ),
          );
        }
        super.initState();
      }
    
      @override
      void dispose() {
    //    _scrollController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return Scrollbar(
          key: PageStorageKey('WidgetD'),
          isAlwaysShown: true,
          showTrackOnHover: true,
    //      controller: _scrollController,
          child: SingleChildScrollView(
    //        controller: _scrollController,
            child: Column(
              children: children,
            ),
          ),
        );
      }
    
      @override
      bool get wantKeepAlive => true;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-08-17
      • 2021-11-15
      • 2020-11-27
      • 1970-01-01
      • 2021-09-02
      • 2021-01-31
      • 2020-12-30
      • 2019-07-08
      • 2020-09-24
      相关资源
      最近更新 更多