flutter 具有动态容器高度的TabBarView

c86crjj0  于 2023-03-19  发布在  Flutter
关注(0)|答案(7)|浏览(458)

这是我的布局结构
这是主屏幕

ListView(
  children: <Widget>[
    _buildCarousel(),
    _buildHomeTabBar(),
  ],
)

这是主页标签栏屏幕

SingleChildScrollView(
  child:
    DefaultTabController(
      length: myTabs.length,
      initialIndex: 0,
      child: Column(
        children: [
          TabBar(
            isScrollable: true,
            tabs: myTabs,
          ),
          Container(
            height: 600,
              child: 
              TabBarView(
                children: [
                  ChildScreen(),
                  ChildScreen2(),
                  ChildScreen3(),
                ],
              )
          )
        ],
      ))
);

我想去掉Container的高度,我们怎么做呢?
ChildScreen从REST获取数据,它实际上是GridView.Builder,因此Container的高度应该是动态的。
抱歉,我错过了ChildScreen的布局实际上是这样的

SingleChildScrollView(
  // shrinkWrap: true,
child: Column(
    children: <Widget>[
        StreamBuilder(
          stream: categoryBloc.categoryList,
          builder: (context, AsyncSnapshot<List<Category>> snapshot){
              if (snapshot.hasData && snapshot!=null) {
                if(snapshot.data.length > 0){
                  return buildCategoryList(snapshot);
                }
                else if(snapshot.data.length==0){
                    return Text('No Data');
                }
              }
              else if (snapshot.hasError) {
                return ErrorScreen(errMessage: snapshot.error.toString());
              }     
              return Center(child: CircularProgressIndicator());

          },
        ),       
    ]
  )
);

所以StreamBuilder里面是GridView.Builder,主要我想去掉Container的高度,在不同的设备上看起来很丑...
因此,如果我删除高度,它将不会显示在屏幕上,并抛出错误
I/扑动(493):#2渲染对象.布局(包:flutter/src/rendering/object.dart:1578:12)I/flutter(493):#3渲染切片列表。执行布局。高级(软件包:flutter/src/rendering/切片列表。dart:200:17)I/flutter(493):#4渲染切片列表.performLayout(软件包:flutter/src/渲染/切片列表.dart:233:19)I/flutter(493):#5渲染对象.布局(包:flutter/src/rendering/object.dart:1634:7)I/flutter(493):#6渲染切片填充.performLayout(软件包:flutter/src/rendering/切片填充.dart:182:11)I/flutter(493):#7渲染对象.布局(包:flutter/src/rendering/object.dart:1634:7)I/flutter(493):#8渲染视口基础.layoutChildSequence(软件包:flutter/src/渲染/视口.dart:405:13)I/flutter(493):#9渲染视图布局(软件包:flutter/src/rendering/viewport.dart:1316:12)I/flutter(493):#10渲染视口.performLayout(软件包:flutter/src/渲染/视口.dart:1234:20)I/flutter(493):#11渲染对象.布局(包:flutter/src/rendering/object.dart:1634:7)I/flutter(493):#12_渲染代理盒和渲染代理盒和渲染对象与儿童混合和渲染代理盒混合.performLayout(软件包:flutter/src/rendering/proxy_box.dart:104:13)I/flutter(493):#13渲染对象.layout(软件包:flutter/src/rendering/object.dart:1634:7)

tv6aics1

tv6aics11#

我在我的项目中也有类似的任务,问题的根源是你试图把TabBarView(可滚动的小部件,试图尽可能大),放在一个列小部件中,没有高度。
解决方案之一是去掉在ListView + Column示例中 Package TabBarView的可滚动小部件,并使用NestedScrollView代替它们。您需要将_buildCarousel()TabBar放在headerSliverBuilder部分中,将TabBarView放在NestedScrollView的主体中。
我不知道你的设计看起来怎么样,但是NestedScrollView默认打开100%的屏幕视图高度,所以如果你想让所有东西都在一个屏幕上,当需要的时候,通过改变ScrollController的行为来阻止滚动会更容易。
在这个例子中,我阻止了第三个标签页的滚动,但是你可以检查网格视图的最后一个项目的可见性。只需添加关键字到最后一个项目,并检查其在屏幕上的位置。
希望能帮上忙。

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  final bodyGlobalKey = GlobalKey();
  final List<Widget> myTabs = [
    Tab(text: 'auto short'),
    Tab(text: 'auto long'),
    Tab(text: 'fixed'),
  ];
  TabController _tabController;
  ScrollController _scrollController;
  bool fixedScroll;

  Widget _buildCarousel() {
    return Stack(
      children: <Widget>[
        Placeholder(fallbackHeight: 100),
        Positioned.fill(child: Align(alignment: Alignment.center, child: Text('Slider'))),
      ],
    );
  }

  @override
  void initState() {
    _scrollController = ScrollController();
    _scrollController.addListener(_scrollListener);
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener(_smoothScrollToTop);

    super.initState();
  }

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

  _scrollListener() {
    if (fixedScroll) {
      _scrollController.jumpTo(0);
    }
  }

  _smoothScrollToTop() {
    _scrollController.animateTo(
      0,
      duration: Duration(microseconds: 300),
      curve: Curves.ease,
    );

    setState(() {
      fixedScroll = _tabController.index == 2;
    });
  }

  _buildTabContext(int lineCount) => Container(
        child: ListView.builder(
          physics: const ClampingScrollPhysics(),
          itemCount: lineCount,
          itemBuilder: (BuildContext context, int index) {
            return Text('some content');
          },
        ),
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        controller: _scrollController,
        headerSliverBuilder: (context, value) {
          return [
            SliverToBoxAdapter(child: _buildCarousel()),
            SliverToBoxAdapter(
              child: TabBar(
                controller: _tabController,
                labelColor: Colors.redAccent,
                isScrollable: true,
                tabs: myTabs,
              ),
            ),
          ];
        },
        body: Container(
          child: TabBarView(
            controller: _tabController,
            children: [_buildTabContext(2), _buildTabContext(200), _buildTabContext(2)],
          ),
        ),
      ),
    );
  }
}


.
另一种方法是创建自定义的TabView小部件。

ogq8wdun

ogq8wdun2#

如果您也得到错误扩展,那么不要使用TabBarView创建自定义TabBarView
1.从onTap获取索引,是TabBar的属性。
1.然后在onTap函数中使用if else,选择哪个索引,并用索引初始化全局变量。
1.然后使用构建器窗口小部件来构建你的TabBarView。同样,在构建器中,你将使用if else来获取所选的索引。然后在if else中返回你的小部件。
在这种情况下,你可以得到你的小部件的最大或最小高度。你不需要指定容器高度。
_selectedTabBar是全局变量

Column(children: [
               TabBar(
                       onTap: (index) {
                          print(index);                                  
                          setState(() {
                                _selectedTabbar = index;
                          });
                        },
                        tabs: [
                          Tab(
                            text: 'Tab1',
                          ),
                          Tab(
                            text: 'Tab2',
                          ),
                          Tab(
                            text: 'Tab3',
                          ),
                        ],
                      ),
                    
                      Builder(builder: (_) {
                        if (_selectedTabbar == 0) {
                          return Container();//1st custom tabBarView
                        } else if (_selectedTabbar == 1) {
                          return Container();//2nd tabView
                        } else {
                          return Container(); //3rd tabView
                        }
                      }),
]
)
wljmcqd8

wljmcqd83#

工作溶液:您需要在两个位置进行扩展
1.高于默认选项卡控制器。
1.容器的容器。

Expanded(
    child: Container(
        decoration: BoxDecoration(
          border: Border(
              top: BorderSide(
                  color: Colors.grey, width: 0.5))),
        child: TabBarView(
          children: <Widget>[
              Container(),
              Container(),
              Container(),
        ])),),

一个不够。

vs3odd8k

vs3odd8k4#

1-您需要将内容添加到列表中
2-然后将tabBarView放入容器中
3-假设您的项目有一个固定的高度,将容器的高度定义为小部件的高度,然后乘以当前索引内容或列表长度
例如:x1月1x

cdmah0mi

cdmah0mi5#

使用Expanded小部件 Package 列表视图:
使用Expanded小工具可扩展RowColumnFlex的子项,以填充主轴中的可用空间(例如,水平扩展行或垂直扩展列)。如果扩展了多个子项,则可用空间将根据弹性因子在它们之间进行分配。

Expanded(
  child: ListView.builder(
  itemCount: 120,
  itemExtent: 32,
  itemBuilder: (BuildContext context, int index) {
    return new Row(
      children: <Widget>[
        Icon(Icons.access_alarm),
        Text(' Entry $index'),
      ],
    );
  },
))
oiopk7p5

oiopk7p56#

我有相同的要求,但需要显示动态高度的标签栏在底部工作表,所以我尝试下面的代码,它与我完美的工作

class BottomSheetScreen extends StatefulWidget {
  @override
  _BottomSheetScreenState createState() => _BottomSheetScreenState();
}

class _BottomSheetScreenState extends State<BottomSheetScreen>
    with SingleTickerProviderStateMixin {

  late TabController _tabController;
  int _selectedTabbar = 0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        child: const Text('showModalBottomSheet'),
        onPressed: () {
          showModalBottomSheet(
            context: context,
            builder: (BuildContext context) {
              return StatefulBuilder(
                  builder: (BuildContext context, StateSetter setState) {
                return Wrap(
                  children: [
                    Column(children: [
                      TabBar(
                        controller: _tabController,
                        onTap: (index) {
                          print(index);
                          setState(() {
                            _selectedTabbar = index;
                          });
                        },
                        tabs: [
                          Tab(text: 'Tab1'),
                          Tab(text: 'Tab2'),
                          Tab(text: 'Tab3'),
                        ],
                      ),
                      IntrinsicHeight(
                        child: Column(
                          children: [
                            _selectedTabbar == 0 ? Text("Tab1 content") : _selectedTabbar == 1 ? Text("Tab2 content") : Text("Tab3 content"),
                          ],
                        ),
                      ),
                      SizedBox(height: 10),
                      Text("bottom content"),
                    ]),
                  ],
                );
              });
            },
          );
        },
      ),
    );
  }
}
mnowg1ta

mnowg1ta7#

默认TabBarView不允许具有动态高度的子级。此包尝试通过扩展默认TabBarView并进行所需更改来解决此问题。AutoScaleTabBarView允许具有动态高度的子级。您可以使用此autoscale_tabbarview库来解决此问题。
首先,在终端中运行以下命令

flutter pub add autoscale_tabbarview

然后,将其导入到dart文件中

import 'package:autoscale_tabbarview/autoscale_tabbarview.dart';

最后,将TabBarView替换为AutoScaleTabbarView,并从容器中删除height

相关问题