Saltar al contenido

¿Cómo crear un TabBarView dinámico / Renderizar una nueva pestaña con una función en Flutter?

No busques más por otros sitios ya que estás al espacio justo, tenemos la solución que necesitas sin complicaciones.

Solución:

Surgen problemas si necesita modificar las matrices. Consisten en que al modificar un array no tiene la oportunidad de utilizar el mismo controlador.

ingrese la descripción de la imagen aquí

Puede utilizar el siguiente widget personalizado para este caso:

import 'package:flutter/material.dart';

  void main() => runApp(MyApp());

  class MyApp extends StatelessWidget 
    @override
    Widget build(BuildContext context) 
      return MaterialApp(
        title: 'Flutter Demo',
        home: MyHomePage(),
      );
    
  

  class MyHomePage extends StatefulWidget 
    @override
    _MyHomePageState createState() => _MyHomePageState();
  

  class _MyHomePageState extends State 
    List data = ['Page 0', 'Page 1', 'Page 2'];
    int initPosition = 1;

    @override
    Widget build(BuildContext context) 
      return Scaffold(
        body: SafeArea(
          child: CustomTabView(
            initPosition: initPosition,
            itemCount: data.length,
            tabBuilder: (context, index) => Tab(text: data[index]),
            pageBuilder: (context, index) => Center(child: Text(data[index])),
            onPositionChange: (index)
              print('current position: $index');
              initPosition = index;
            ,
            onScroll: (position) => print('$position'),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () 
            setState(() 
              data.add('Page $data.length');
            );
          ,
          child: Icon(Icons.add),
        ),
      );
    
  

  /// Implementation

  class CustomTabView extends StatefulWidget 
    final int itemCount;
    final IndexedWidgetBuilder tabBuilder;
    final IndexedWidgetBuilder pageBuilder;
    final Widget stub;
    final ValueChanged onPositionChange;
    final ValueChanged onScroll;
    final int initPosition;

    CustomTabView(
      @required this.itemCount,
      @required this.tabBuilder,
      @required this.pageBuilder,
      this.stub,
      this.onPositionChange,
      this.onScroll,
      this.initPosition,
    );

    @override
    _CustomTabsState createState() => _CustomTabsState();
  

  class _CustomTabsState extends State with TickerProviderStateMixin 
    TabController controller;
    int _currentCount;
    int _currentPosition;

    @override
    void initState() 
      _currentPosition = widget.initPosition ?? 0;
      controller = TabController(
        length: widget.itemCount,
        vsync: this,
        initialIndex: _currentPosition,
      );
      controller.addListener(onPositionChange);
      controller.animation.addListener(onScroll);
      _currentCount = widget.itemCount;
      super.initState();
    

    @override
    void didUpdateWidget(CustomTabView oldWidget) 
      if (_currentCount != widget.itemCount) 
        controller.animation.removeListener(onScroll);
        controller.removeListener(onPositionChange);
        controller.dispose();

        if (widget.initPosition != null) 
          _currentPosition = widget.initPosition;
        

        if (_currentPosition > widget.itemCount - 1) 
            _currentPosition = widget.itemCount - 1;
            _currentPosition = _currentPosition < 0 ? 0 : 
            _currentPosition;
            if (widget.onPositionChange is ValueChanged) 
               WidgetsBinding.instance.addPostFrameCallback((_)
                if(mounted) 
                  widget.onPositionChange(_currentPosition);
                
               );
            
         

        _currentCount = widget.itemCount;
        setState(() 
          controller = TabController(
            length: widget.itemCount,
            vsync: this,
            initialIndex: _currentPosition,
          );
          controller.addListener(onPositionChange);
          controller.animation.addListener(onScroll);
        );
       else if (widget.initPosition != null) 
        controller.animateTo(widget.initPosition);
      

      super.didUpdateWidget(oldWidget);
    

    @override
    void dispose() 
      controller.animation.removeListener(onScroll);
      controller.removeListener(onPositionChange);
      controller.dispose();
      super.dispose();
    

    @override
    Widget build(BuildContext context) 
      if (widget.itemCount < 1) return widget.stub ?? Container();

      return Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
            alignment: Alignment.center,
            child: TabBar(
              isScrollable: true,
              controller: controller,
              labelColor: Theme.of(context).primaryColor,
              unselectedLabelColor: Theme.of(context).hintColor,
              indicator: BoxDecoration(
                border: Border(
                  bottom: BorderSide(
                    color: Theme.of(context).primaryColor,
                    width: 2,
                  ),
                ),
              ),
              tabs: List.generate(
                widget.itemCount,
                    (index) => widget.tabBuilder(context, index),
              ),
            ),
          ),
          Expanded(
            child: TabBarView(
              controller: controller,
              children: List.generate(
                widget.itemCount,
                    (index) => widget.pageBuilder(context, index),
              ),
            ),
          ),
        ],
      );
    

    onPositionChange() 
      if (!controller.indexIsChanging) 
        _currentPosition = controller.index;
        if (widget.onPositionChange is ValueChanged) 
          widget.onPositionChange(_currentPosition);
        
      
    

    onScroll() 
      if (widget.onScroll is ValueChanged) 
        widget.onScroll(controller.animation.value);
      
    
  

Prueba esto.
Manifestación

Para hacer una pestaña dinámica, puede usar una Lista y seguir agregando la lista en cada clic de botón.

Truco: borre la lista y vuelva a dibujar un widget vacío y vuelva a dibujar los widgets según su lista.

 import 'package:flutter/material.dart';
void main() 
  runApp(new MaterialApp(
    home: new CardStack(),
  ));


class DynamicTabContent 
  IconData icon;
  String tooTip;

  DynamicTabContent.name(this.icon, this.tooTip);


class CardStack extends StatefulWidget 
  @override
  _MainState createState() => new _MainState();


class _MainState extends State with TickerProviderStateMixin 
  List myList = new List();

  TabController _cardController;

  TabPageSelector _tabPageSelector;

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

    myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
    myList.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));

    _cardController = new TabController(vsync: this, length: myList.length);
    _tabPageSelector = new TabPageSelector(controller: _cardController);
  

  @override
  void dispose() 
    _cardController.dispose();
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      backgroundColor: Colors.grey[300],
      appBar: new AppBar(
          actions: [
            new Padding(
              padding: const EdgeInsets.all(1.0),
              child: new IconButton(
                icon: const Icon(
                  Icons.add,
                  size: 30.0,
                  color: Colors.white,
                ),
                tooltip: 'Add Tabs',
                onPressed: () 
                  List tempList = new List();

                  myList.forEach((dynamicContent) 
                    tempList.add(dynamicContent);
                  );

                  setState(() 
                    myList.clear();
                  );

                  if (tempList.length % 2 == 0) 
                    myList.add(new DynamicTabContent.name(Icons.shopping_cart, "shopping cart"));
                   else 
                    myList.add(new DynamicTabContent.name(Icons.camera, "camera"));
                  

                  tempList.forEach((dynamicContent) 
                    myList.add(dynamicContent);
                  );

                  setState(() 
                    _cardController = new TabController(vsync: this, length: myList.length);
                    _tabPageSelector = new TabPageSelector(controller: _cardController);
                  );
                ,
              ),
            ),
          ],
          title: new Text("Title Here"),
          bottom: new PreferredSize(
              preferredSize: const Size.fromHeight(10.0),
              child: new Theme(
                data: Theme.of(context).copyWith(accentColor: Colors.grey),
                child: myList.isEmpty
                    ? new Container(
                        height: 30.0,
                      )
                    : new Container(
                        height: 30.0,
                        alignment: Alignment.center,
                        child: _tabPageSelector,
                      ),
              ))),
      body: new TabBarView(
        controller: _cardController,
        children: myList.isEmpty
            ? []
            : myList.map((dynamicContent) 
                return new Card(
                  child: new Container(
                      height: 450.0,
                      width: 300.0,
                      child: new IconButton(
                        icon: new Icon(dynamicContent.icon, size: 100.0),
                        tooltip: dynamicContent.tooTip,
                        onPressed: null,
                      )),
                );
              ).toList(),
      ),
    );
  

Espero que esto ayude 🙂

Si eres capaz, eres capaz de dejar un post acerca de qué te ha parecido este ensayo.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *