Невозможно установить динамическую высоту для TabBarView во флаттере

Я пытаюсь создать TabBar, который будет расположен посередине страницы (виджет описания должен быть вверху).

Проблема в том, что мне нужно вручную установить высоту виджета «Контейнер», который содержит TabBarView. Если я оставлю его без этой высоты, я получу ошибку Horizontal viewport was given unbounded height..

Виджет верхнего уровня:

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[Description(), Tabs()],
        ),
      ),
    );
  }

Виджет вкладок:

class Tabs extends StatelessWidget {
  final _tabs = [
    Tab(
      icon: Icon(Icons.menu),
      text: 'Menu',
    ),
    Tab(
      icon: Icon(Icons.mode_comment),
      text: 'Reviews',
    )
  ];

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        length: _tabs.length,
        child: Column(
          children: <Widget>[
            TabBar(
              labelColor: PickColors.black,
              indicatorSize: TabBarIndicatorSize.tab,
              tabs: _tabs,
            ),
            Container(
              width: double.infinity,
              height: 200, // I need to remove this and make height dynamic
              child: TabBarView(
                children: <Widget>[MenuTab(), ReviewsTab()],
              ),
            ),
          ],
        ));
  }
}

Поскольку содержимое вкладок будет динамическим, высота также будет. Я не могу использовать здесь статическую высоту.

Есть ли альтернатива Контейнеру со статической высотой? Как сделать высоту вкладок динамической?


person zilijonas    schedule 07.09.2019    source источник
comment
@ Евгений не помог. любые другие идеи?   -  person zilijonas    schedule 08.09.2019


Ответы (3)


Я исправил эту проблему, изменив SingleChildScrollView на ListView и написав собственный виджет TabView, который содержит вкладки в оболочке Stack.

Обертки тела виджета верхнего уровня изменены с Column и SingleChildScrollView на ListView:

  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Scaffold(
      appBar: RestaurantInfoAppBar(),
      body: ListView(
        children: <Widget>[Description(), Tabs()],
      ),
    );
  }

Виджет вкладок - удален Контейнер со статической оберткой ширины:

  Widget build(BuildContext context) {
    return DefaultTabController(
        length: _tabs.length,
        child: Column(
          children: <Widget>[
            TabBar(
              labelColor: PickColors.black,
              indicatorSize: TabBarIndicatorSize.tab,
              tabs: _tabs,
            ),
            TabsView(
              tabIndex: _tabIndex,
              firstTab: MenuTab(),
              secondTab: ReviewsTab(),
            )
          ],
        ));
  }

Новый пользовательский компонент TabsView в настоящее время обрабатывает только две вкладки (так как мне нужно только две), но его можно легко изменить для обработки динамического числа вкладок:

class TabsView extends StatelessWidget {
  TabsView(
      {Key key,
      @required this.tabIndex,
      @required this.firstTab,
      @required this.secondTab})
      : super(key: key);

  final int tabIndex;
  final Widget firstTab;
  final Widget secondTab;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        AnimatedContainer(
          child: firstTab,
          width: SizeConfig.screenWidth,
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
          transform: Matrix4.translationValues(
              tabIndex == 0 ? 0 : -SizeConfig.screenWidth, 0, 0),
          duration: Duration(milliseconds: 300),
          curve: Curves.easeIn,
        ),
        AnimatedContainer(
          child: secondTab,
          width: SizeConfig.screenWidth,
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
          transform: Matrix4.translationValues(
              tabIndex == 1 ? 0 : SizeConfig.screenWidth, 0, 0),
          duration: Duration(milliseconds: 300),
          curve: Curves.easeIn,
        )
      ],
    );
  }
}

P.S. SizeConfig совпадает с MediaQuery.of (context) .size.width.

Надеюсь, это поможет кому-то вроде меня! :)

person zilijonas    schedule 10.09.2019
comment
Любым другим путем? это кастомный виджет, не поддерживающий swype :) - person lacas; 01.04.2020
comment
Как изменить _tabIndex при изменении вкладок в приведенном выше примере? - person Mrinal Jain; 28.07.2020
comment
TabsView принимает высоту вкладки с большим содержанием, из-за этого на другой вкладке с меньшим содержанием есть пустое пространство. Какое-нибудь решение? - person Mrinal Jain; 28.07.2020
comment
вы можете изменить _tabIndexby с помощью TabController _tabController. Я решил это с помощью саженца в начале. stackoverflow.com/a/62813551/5319007 - person Alex Trujillo; 22.04.2021
comment
Отличная идея AnimatedContainer. Работает как шарм - person lenz; 10.07.2021

Вы можете обернуть TabBarView виджетом Expanded.

Убедитесь, что вы используете правильные родительские и дочерние виджеты для TabBarView

Я знаю, что уже поздно, надеюсь, это кому-то поможет.

person ranul    schedule 03.07.2020

Я нашел, что это нормально работает со мной

import 'package:cdc/ui/shared/app_color.dart';
import 'package:flutter/material.dart';

class OrderDetails extends StatefulWidget {
  @override
  _OrderDetailsState createState() => _OrderDetailsState();
}

class _OrderDetailsState extends State<OrderDetails>
    with SingleTickerProviderStateMixin {
  final List<Widget> myTabs = [
    Tab(text: 'one'),
    Tab(text: 'two'),
  ];

  TabController _tabController;
  int _tabIndex = 0;

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

  @override
  void initState() {
    _tabController = TabController(length: 2, vsync: this);
    _tabController.addListener(_handleTabSelection);
    super.initState();
  }

  _handleTabSelection() {
    if (_tabController.indexIsChanging) {
      setState(() {
        _tabIndex = _tabController.index;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Order Detials'),
        backgroundColor: kPrimaryColor,
      ),
      body: ListView(
        padding: EdgeInsets.all(15),
        children: <Widget>[
          Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(14.0),
              color: const Color(0xffffffff),
              boxShadow: [
                BoxShadow(
                  color: const Color(0x2e000000),
                  offset: Offset(0, 0),
                  blurRadius: 10,
                ),
              ],
            ),
            child: Column(
              children: <Widget>[
                TabBar(
                  controller: _tabController,
                  labelColor: Colors.redAccent,
                  tabs: myTabs,
                ),
                Container(
                  child: [
                    Text('First tab'),
                    Column(
                      children:
                          List.generate(20, (index) => Text('line: $index'))
                              .toList(),
                    ),
                  ][_tabIndex],
                ),
              ],
            ),
          ),
          Container(child: Text('another component')),
        ],
      ),
    );
  }
}
person Sohel Mahmud    schedule 09.07.2020