Добавление пользовательского виджета на активную вкладку панели вкладок Flutter

#flutter #tabbar

Вопрос:

Мне нужна панель вкладок и представление вкладок, как описано в https://flutter.dev/docs/cookbook/design/tabs , но есть один нюанс: мне нужна АКТИВНАЯ вкладка, чтобы показать дополнительный пользовательский виджет.

Если пользователь переключается на другую вкладку, мне нужно, чтобы пользовательский виджет исчез с ранее активной вкладки, а на новой активной вкладке появился НОВЫЙ пользовательский виджет.

Другой способ объяснить это: на всех вкладках должен быть размещен экземпляр моего пользовательского виджета, но пользовательские виджеты должны быть скрыты на всех, кроме активной вкладки.

Как этого добиться, пожалуйста?

Большое спасибо

Ответ №1:

Все дело в управлении состоянием. Я сделал пример использования AnimatedBuilder с помощью a TabController , но вы можете настроить его в соответствии с вашими потребностями.

Имейте в виду: думайте декларативно, это поможет вам создать экран любого типа с любой бизнес-логикой.

Шаги:

  • Получить текущий индекс
  • Прослушивание изменений текущего индекса на всех вкладках
  • Проверьте, соответствует ли индекс вкладки текущему выбранному индексу
    • Если это так, отобразите пользовательский виджет
    • В противном случае просто игнорируйте, ничего не создавайте

Ссылка на Dartpad

 import 'package:flutter/material.dart';

void main() {
  runApp(const TabBarDemo());
}

class TabBarDemo extends StatefulWidget {
  const TabBarDemo({Key? key}) : super(key: key);

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

class _TabBarDemoState extends State<TabBarDemo>
    with SingleTickerProviderStateMixin {
  late final TabController _controller;

  @override
  void initState() {
    super.initState();

    _controller = TabController(length: 3, vsync: this, initialIndex: 0);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            controller: _controller,
            tabs: [
              Tab(
                child: AnimatedBuilder(
                  animation: _controller,
                  builder: (context, chiild) {
                    return Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(Icons.directions_car),
                        if (_controller.index == 0) const MyCustomWidget(),
                      ],
                    );
                  },
                ),
              ),
              Tab(
                child: AnimatedBuilder(
                  animation: _controller,
                  builder: (context, chiild) {
                    return Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(Icons.directions_transit),
                        if (_controller.index == 1) const MyCustomWidget(),
                      ],
                    );
                  },
                ),
              ),
              Tab(
                child: AnimatedBuilder(
                  animation: _controller,
                  builder: (context, chiild) {
                    return Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(Icons.directions_bike),
                        if (_controller.index == 2) const MyCustomWidget(),
                      ],
                    );
                  },
                ),
              ),
            ],
          ),
          title: const Text('Tabs Demo'),
        ),
        body: TabBarView(
          controller: _controller,
          children: const [
            Icon(Icons.directions_car),
            Icon(Icons.directions_transit),
            Icon(Icons.directions_bike),
          ],
        ),
      ),
    );
  }
}

class MyCustomWidget extends StatelessWidget {
  const MyCustomWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      child: const Text('Your CustomWidget'),
    );
  }
}
 

Комментарии:

1. Спасибо, очень полезно. Есть ли способ, чтобы каждый MyCustomWidget () определял для себя индекс активной вкладки, чтобы он мог показывать / скрывать себя? Это позволит избежать повторяющегося кода «if (_controller.index == xxxx) const MyCustomWidget()» на каждой вкладке

2. Я должен был сказать «индекс активной вкладки И ее собственный индекс»

3. Да, вы можете добавить цикл for для построения каждой вкладки, и вы будете использовать индекс цикла вместо необработанного индекса, такого как 0, 1, 3, …

Ответ №2:

Tab( ) виджет может содержать любой виджет, а не только Text и icon

Сначала вам нужно определить, какая вкладка была выбрана.

Затем вам нужно выполнить «если» (?), Чтобы решить, какой виджет отображать.

Используйте этот код:

 int selectedTab=1;
    TabBar(
        onTap: (index) {
          selectedTab = index;
        },

        tabs: [
          Tab(
              child: (selectedTab == 1) ? yourCustomWidget1 : yourWidget1
          ),
          Tab(
              child: (selectedTab == 2) ? yourCustomWidget2 : yourWidget2
          ),
        ]);
 

Дайте мне знать, если это не сработает

Комментарии:

1. Спасибо, это полезно, но я почти уверен, что onTap() не сработает, если пользователь проведет пальцем по панели вкладок, чтобы перейти на другую вкладку?