簡體   English   中英

Flutter:SingleChildScrollView 內的 TabBarView

[英]Flutter: TabBarView inside SingleChildScrollView

我的問題是我想要一個 TabBarView 在 SingleChildScrollView 中,但它給了我這個錯誤: RenderFlex children have non-zero flex 但傳入的高度約束是無限的。

如果我刪除SingleChildScrollView它可以工作,但我需要小部件,因為那時我想推送一個 ListView ,它與TabBar一起滾動,比如 Instagram。

代碼:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = new TabController(length: 2, vsync: this);
  }

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: SingleChildScrollView(
      child: Column(
        children: [
          TabBar(
            controller: tabController,
            tabs: [
              Tab(
                icon: Icon(
                  Icons.photo_library,
                  size: 30,
                ),
              ),
              Tab(
                icon: Icon(
                  Icons.perm_media,
                  size: 30,
                ),
              ),
            ],
            labelColor: Colors.deepOrange,
            unselectedLabelColor: Colors.black,
            indicatorColor: Colors.deepOrange,
          ),
          Expanded(
            child: TabBarView(controller: tabController, children: [
              Expanded(child: Container()),
              Expanded(child: Container())
            ]),
          ),
        ],
      ),
    )));
  }
}

變化:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = new TabController(length: 2, vsync: this);
  }

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TabBar(
            controller: tabController,
            tabs: [
              Tab(
                icon: Icon(
                  Icons.photo_library,
                  size: 30,
                ),
              ),
              Tab(
                icon: Icon(
                  Icons.perm_media,
                  size: 30,
                ),
              ),
            ],
            labelColor: Colors.deepOrange,
            unselectedLabelColor: Colors.black,
            indicatorColor: Colors.deepOrange,
          ),
          Expanded(
            child: SingleChildScrollView(child:TabBarView(controller: tabController, children: [
              Container(),
              Container()
            ]),
          ),)
        ],
      ),
    ));
  }
}

您可以使用NestedScrollView來解決此問題。

下面的代碼幫助我解決了:

NestedScrollView(
      headerSliverBuilder: (context, value) {
        return [
          SliverToBoxAdapter(
              child: Header()
          ),
          SliverToBoxAdapter(
            child: TabBar(
              controller: _controller,
              tabs: [
                Tab(icon: Icon(Icons.x)),
                Tab(icon: Icon(Icons.y)),
                Tab(icon: Icon(Icons.z)),
              ],
            ),
          ),
        ];
      },
    body: Container(
      child: TabBarView(
        controller: _controller,
        children: <Widget>[
          page1(),
          page2(),
          page3(),
        ],
      ),
    ),
  )

如需進一步解釋,請參閱此答案

TabBarView 需要 SingleChildScrollView 無法提供的有限高度。 問題是您在 SingleChildScrollView 內的列中使用擴展。


This answer from a similar question可能會對您有所幫助

答案就在錯誤本身。 當列在可滾動的視圖內時,該列正在嘗試收縮包裝其內容,但由於您使用 Expanded 作為該列的子級,它的工作方式與嘗試收縮其子級的列相反。 兩者都試圖完成一個完全相反的任務。 OG

這是導致此錯誤的原因,因為這兩個指令彼此完全相反。 如錯誤日志中所述,請嘗試以下操作:考慮將mainAxisSize設置為MainAxisSize.min (用於列)並使用FlexFit.loose進行靈活擬合(使用 Flexible 而不是 Expanded)。

我遇到了類似的問題。 我的解決方案是使用容器而不是 TabBarView 來顯示子項(選項卡)。

您可以根據通過 TabBar 選擇的索引來切換此容器的內容。

當然,如果您需要滑動手勢在選項卡之間移動,您也需要添加它,對我來說這不是必需的。 代碼看起來像這樣。

import 'package:flutter/material.dart';

class Screen extends StatefulWidget {
  Screen({
    Key key,
  }) : super(key: key);

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

class _ScreenState extends State<Screen> with TickerProviderStateMixin {
  TabController _builderPageController;
  List<Widget> _tabs;
  List<Tab> _tabItems;
  int selectedtabIndex = 0;

  @override
  void initState() {
    super.initState();
    _initTabController();
    _setUpTabComponents();
    _preprareTabItems();
  }

  Column _showWidgets() {
    return Column(
      children: [
        Container(
          // your non tab widgets goes here
          height: 300,
          color: Colors.blueAccent,
        ),
        SizedBox(
          height: 10,
        ),
        Material(
          elevation: 3,
          child: TabBar(
            tabs: _tabItems,
            controller: _builderPageController,
            unselectedLabelColor: Colors.grey,
            labelColor: Colors.blueAccent,
            indicatorColor: Colors.blueAccent,
            labelStyle: TextStyle(
              fontWeight: FontWeight.w500,
              fontSize: 12.0,
            ),
            unselectedLabelStyle: TextStyle(fontWeight: FontWeight.normal, fontSize: 12.0),
          ),
        ),
        Container(
            padding: EdgeInsets.symmetric(horizontal: 16.0),
            child: Builder(
              builder: (context) {
                return _tabs[selectedtabIndex];
              },
            ))
      ],
    );
  }

  void _initTabController() {
    // inits Tabcontroller for Tabview
    _builderPageController = TabController(
      length: 3,
      vsync: this,
      initialIndex: selectedtabIndex,
    );
    _builderPageController.addListener(() {
      // updated index and calls the set state
      // to switch the content of the tab based on the index clicked
      selectedtabIndex = _builderPageController.index;
      setState(() {
        _builderPageController.index;
      });
    });
  }

  void _setUpTabComponents() {
    // sets up Tab headers
    _tabItems = [
      Tab(child: Text('Tab1')),
      Tab(child: Text('Tab2')),
      Tab(child: Text('Tab3')),
    ];
  }

  List<Widget> _preprareTabItems() {
    // views to show on each tab
    // remove height once you add your contents
    return _tabs = <Widget>[
      Container(
        // first tab content
        height: 400,
        color: Colors.white,
      ),
      Container(
        // second tab content
        height: 600,
        color: Colors.white,
      ),
      Container(
        // third  tab content
        height: 900,
        color: Colors.white,
      ),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(child: _showWidgets());
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM