TABBARVIEW在可滚动页面中

发布于 2025-01-19 10:20:40 字数 2784 浏览 4 评论 0原文

我在让布局在 Flutter 中工作时遇到了很大的困难。

我尝试创建的布局:

  • 一个 ListView 包含:
    • 一个容器
    • 一个TabBar
    • 一个 TabBarView,其中每个 TabBarView 包含一个 Column
  • 我希望整个页面可以滚动。

下面是布局的示意图:

示例代码

这是一个最小的示例代码(删除了精确的小部件定义):

return DefaultTabController(
      length: 2,
      child: ListView(
        children: [
          // TOP CONTAINER //
          Container(height: 30),

          // TAB BAR //

          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

          // TAB BAR VIEWS //
          SizedBox(
            height: MediaQuery.of(context).size.height,
            child: TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),
          )
        ],
      ),
    );

问题

当窗口的高度变小时,我在底部收到溢出错误:

我所做的

  • 我首先尝试将内部 Column 转换为 ListView,这修复了溢出,但导致两个单独的可滚动区域(单个选项卡视图和整个选项卡视图)页),这不是我想要的 - 我想要一个可滚动区域。将此 ListViewphysicals 属性设置为 NeverScrollablePhysics() 并不能解决此问题,并会导致一些奇怪的行为。
  • 我尝试使用 NestedScrollViewSilvers (来自 如何创建有界可滚动 TabBarView)。但这会导致在浏览选项卡时出现以下异常:提供的 ScrollController 当前附加到多个 ScrollPosition。,并产生一些不可靠的滚动机制。
  • 我尝试使用 CustomScrollView 但这不起作用。

未提供有效解决方案的类似问题:

我很困惑为什么它不起作用,因为我觉得这是一件非常简单的事情。本质上,它与查看个人资料时 Instragram 应用程序(以及其他应用程序)中使用的布局相同(请参阅:https://unblast.com/wp-content/uploads/2020/01/Instagram-UI-Profile-1.jpg)。

I am having real trouble getting a layout to work within Flutter.

The layout I am trying to create:

  • A ListView that contains a:
    • A Container.
    • A TabBar.
    • A TabBarView, where each TabBarView contains a Column.
  • And I want the whole page to be scrollable.

Here is the schematic for the layout:

Example Code

Here is a minimum example code (with exact widget definitions removed):

return DefaultTabController(
      length: 2,
      child: ListView(
        children: [
          // TOP CONTAINER //
          Container(height: 30),

          // TAB BAR //

          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

          // TAB BAR VIEWS //
          SizedBox(
            height: MediaQuery.of(context).size.height,
            child: TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),
          )
        ],
      ),
    );

The Problem:

When the height of the window gets smaller, I get an overflow error at the bottom:

What I have Done:

  • I first tried converting the inner Column into a ListView, which fixed the overflow, but resulted in two separate scrollable areas (the individual tab views and the whole page), which is not what I want - I want a single scrollable area. Setting the physics property of this ListView to NeverScrollablePhysics() doesnt fix this and results in some weird behaviour.
  • I tried using a NestedScrollView with Silvers (from How to create a bounded scrollable TabBarView). But this results in the following exception when navigating through the tabs: The provided ScrollController is currently attached to more than one ScrollPosition., and produces some dodgy scroll mechanics.
  • I tried using a CustomScrollView but that didnt work.

Similar Questions that Didnt provide a working solution:

I am very confused as to why it is not working as I feel this is a very simple thing. Essentially, it is the same layout used in the Instragram app (among others) when viewing your personal profile (see: https://unblast.com/wp-content/uploads/2020/01/Instagram-UI-Profile-1.jpg).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

囍笑 2025-01-26 10:20:40

从注释中,您可以将页面包装在 singlechildscrollview 中,禁用列表视图的滚动物理,因为父级已经可滚动。

return SingleChildScrollView(
  child: DefaultTabController(
    length: 2,
    child: ListView(
      physics: NeverScrollableScrollPhysics(),
        children: [
          // TOP CONTAINER //
          Container(height: 30),

          // TAB BAR //
          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

          // TAB BAR VIEWS //
          SizedBox(
            height: MediaQuery.of(context).size.height,
            child: TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),
          )
        ],
      ),
    ));

**选项2 **

您可以使用customScrollViewnestedScrollView

DefaultTabController(
      length: 2,
      child:
CustomScrollView(
              slivers: [

SlivertoboxAdapter(child:   // TOP CONTAINER //
          Container(height: 30),

SlivertoboxAdapter(child:   // TAB BAR //

          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

//... Sliverfillremaining/slivettoboxadapter for your tabbarview

SlivertoboxAdapter(child:TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),




From the comments you can wrap your page in a singlechildscrollview, disable scroll physics for the listview as the parent is already scrollable.

return SingleChildScrollView(
  child: DefaultTabController(
    length: 2,
    child: ListView(
      physics: NeverScrollableScrollPhysics(),
        children: [
          // TOP CONTAINER //
          Container(height: 30),

          // TAB BAR //
          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

          // TAB BAR VIEWS //
          SizedBox(
            height: MediaQuery.of(context).size.height,
            child: TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),
          )
        ],
      ),
    ));

** Option2 **

you can use a customScrollView or a nestedScrollView

DefaultTabController(
      length: 2,
      child:
CustomScrollView(
              slivers: [

SlivertoboxAdapter(child:   // TOP CONTAINER //
          Container(height: 30),

SlivertoboxAdapter(child:   // TAB BAR //

          const TabBar(tabs: [
            Tab(child: Text("Tab 1")),
            Tab(child: Text("Tab 2")),
          ]),

//... Sliverfillremaining/slivettoboxadapter for your tabbarview

SlivertoboxAdapter(child:TabBarView(
              children: [
                Container(height: 5000),
                Container(height: 5000),
              ],
            ),




心是晴朗的。 2025-01-26 10:20:40

我已经在tabbarview上划过了一个问题。

不幸的是,它在滚动诸如滚动和无法正常工作的用例中被打破,内容溢出。

因此,我的解决方案通过回答如何滚动整个页面来回答OP问题。它用不同的机制代替TABBARVIEW

我的解决方案是跳过tabbarview并使用tabbartabControllerwidget < /代码>列表。

代码:

// STATEFUL WIDGET CODE

late TabController tabController; // USED FOR NAVIGATION

@override
void initState() {
  tabController = TabController(
    initialIndex: 0,
    length: 3, // adjust your length
    vsync: this,
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('test')), // some app bar
    body: SingleChildScrollView(
      child: Column(
        children: [
          TabBar(controller: tabController),
          _getTabAtIndex(tabContoller.index),
        ],
      ),
    ),
  );
}

Widget _getTabAtIndex(int index) {
  var list = [
    Container(), // FIRST ITEM
    Container(), // SECOND ITEM
    Container(), // THIRD ITEM
  ];

  return list[index];
}

I have scratched my head around TabBarView many times with a question 'How to put dynamic-height content inside TabBarView while it is inside a scrollable container?'

Unfortunately, it is broken for such use cases as the scroll and does not work correctly and the content overflows.

Hence, my solution answers the OP question by answering how to achieve the whole page scrollable. It replaces TabBarView with different mechanism.

My solution is to skip TabBarView and use TabBar and TabController to get a Widget from the Widget list.

Code:

// STATEFUL WIDGET CODE

late TabController tabController; // USED FOR NAVIGATION

@override
void initState() {
  tabController = TabController(
    initialIndex: 0,
    length: 3, // adjust your length
    vsync: this,
  );
  super.initState();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: const Text('test')), // some app bar
    body: SingleChildScrollView(
      child: Column(
        children: [
          TabBar(controller: tabController),
          _getTabAtIndex(tabContoller.index),
        ],
      ),
    ),
  );
}

Widget _getTabAtIndex(int index) {
  var list = [
    Container(), // FIRST ITEM
    Container(), // SECOND ITEM
    Container(), // THIRD ITEM
  ];

  return list[index];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文