且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

具有动态容器高度的 TabBarView

更新时间:2023-01-23 12:44:42

我的项目中有类似的任务.问题的根源是您试图将 TabBarView(试图尽可能大的可滚动小部件)放在没有高度的列小部件中.

I had similar task at my project. The root of the problem is that you are trying to put TabBarView (scrollable widget that trying to be as big as possible), in a column widget, that have no height.

其中一个解决方案是在此示例 ListView + Column 中去掉包裹 TabBarView 的可滚动小部件.并使用 NestedScrollView 代替它们.您需要将 _buildCarousel()TabBar 放在 headerSliv​​erBuilder 部分,并将 TabBarView 放在 NestedScrollView.

One of solutions is get rid of scrollable widgets that wraps your TabBarView in this example ListView + Column. And use NestedScrollView instead of them. You need to put _buildCarousel() and TabBar in the headerSliverBuilder part, and TabBarView inside the body of NestedScrollView.

我不知道您的设计看起来如何,但 NestedScrollView 默认情况下会打开 100% 的屏幕视图高度.因此,如果您想使所有内容都在一个屏幕上,只需在需要时更改 ScrollController 行为即可更轻松地阻止滚动.

I don't know how is your design looks, but NestedScrollView by default opens up to 100% height of screen view. So if you want to make an effect that everything is on one screen, it easer to just block scrolling, by change ScrollController behavior when it’s needed.

在此示例中,我阻止了第三个选项卡上的滚动,但您可以检查网格视图的最后一项的可见性.只需将键添加到最后一项,并检查其在屏幕上的位置.

In this example I’m blocking scrolling on third tab, but you can check visibility of the last item of the grid view. Just add the key to the last item, and check its position on the screen.

希望对你有所帮助.

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 小部件.

Another way to get what you want could be creating custom TabView widget.