When using TabBar in Flutter, how can I set the tab to change or not according to my own constraints?

huangapple go评论106阅读模式
英文:

When using TabBar in Flutter, how can I set the tab to change or not according to my own constraints?

问题

When using TabBar in Flutter, how can I set the tab to change or not according to my own constraints?

For example:

bool tabChangeable() {
    return _formKey.currentState!.validate();
}

When the index changed, I went back to the old index and made my checks and changed the index again according to the current situation. However, when this method is applied, it enters an infinite loop because of the _tabController.animateTo(previousIndex) code.

_tabController.addListener(() {
  if (_tabController.indexIsChanging) {
    int newIndex = _tabController.index;
    int previousIndex = _tabController.previousIndex;
    _tabController.animateTo(previousIndex);
    if (_formKey.currentState!.validate()) {
      _tabController.animateTo(newIndex);
    }
  }
});

I can't use a TabView because my height value is not fixed. I use the widget below instead.

class _LayoutBody extends StatefulWidget {
  const _LayoutBody({
    Key? key,
    required this.tabController,
    required this.tabChildren,
  }) : super(key: key);

  final TabController tabController;
  final List<Widget> tabChildren;

  @override
  State<_LayoutBody> createState() => _LayoutBodyState();
}

class _LayoutBodyState extends State<_LayoutBody> {
  @override
  void initState() {
    super.initState();
    widget.tabController.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return widget.tabChildren[widget.tabController.index];
  }
}

If there is TabView usage for different heights, I would appreciate it if you could write it down. Thanks everyone.

英文:

When using TabBar in Flutter, how can I set the tab to change or not according to my own constraints?

For example:

bool tabChangeable() {
    return _formKey.currentState!.validate();
}

When the index changed, I went back to the old index and made my checks and changed the index again according to the current situation. However, when this method is applied, it enters an infinite loop because of the _tabController.animateTo(previousIndex) code.

_tabController.addListener(() {
  if (_tabController.indexIsChanging) {
    int newIndex = _tabController.index;
    int previousIndex = _tabController.previousIndex;
    _tabController.animateTo(previousIndex);
    if (_formKey.currentState!.validate()) {
      _tabController.animateTo(newIndex);
    }
  }
});

--- Edit

I can't use a TabView because my height value is not fixed. I use the widget below instead.

class _LayoutBody extends StatefulWidget {
  const _LayoutBody({
    Key? key,
    required this.tabController,
    required this.tabChildren,
  }) : super(key: key);

  final TabController tabController;
  final List&lt;Widget&gt; tabChildren;

  @override
  State&lt;_LayoutBody&gt; createState() =&gt; _LayoutBodyState();
}

class _LayoutBodyState extends State&lt;_LayoutBody&gt; {
  @override
  void initState() {
    super.initState();
    widget.tabController.addListener(() {
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return widget.tabChildren[widget.tabController.index];
  }
}

If there is TabView usage for different heights, I would appreciate it if you could write it down. Thanks everyone

答案1

得分: 0

Flirty setting physics: const NeverScrollableScrollPhysics(), to disable the swap changes(mostly needed). Then use the TabController to change the tab only on validation, Here is a demo example

class FTExample extends StatefulWidget {
  const FTExample({super.key});

  @override
  State&lt;FTExample&gt; createState() =&gt; _FTExampleState();
}

class _FTExampleState extends State&lt;FTExample&gt;
    with SingleTickerProviderStateMixin {
  final formKey = GlobalKey&lt;FormState&gt;();
  late final tabController = TabController(length: 3, vsync: this);

  @override
  Widget build(BuildContext context) {
    // tabbar
    return Scaffold(
      appBar: AppBar(
        title: const Text(&#39;TabBar&#39;),
      ),
      body: Column(
        children: [
          TabBar(
            controller: tabController,
            tabs: [
              Tab(
                icon: Icon(Icons.directions_car),
              ),
              Tab(
                icon: Icon(Icons.directions_transit),
              ),
              Tab(
                icon: Icon(Icons.directions_bike),
              ),
            ],
          ),
          Expanded(
            child: TabBarView(
              physics: const NeverScrollableScrollPhysics(), // 用这个设置禁用切换效果(通常需要)
              controller: tabController,
              children: [
                //Form with a TextFiled and button
                Form(
                  key: formKey,
                  child: Column(
                    children: [
                      TextFormField(
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            return &#39;Please enter some text&#39;;
                          }
                          return null;
                        },
                        decoration: InputDecoration(
                          labelText: &#39;Name&#39;,
                          hintText: &#39;Enter your name&#39;,
                        ),
                      ),
                      ElevatedButton(
                        onPressed: () {
                          if (formKey.currentState?.validate() == true) {
                            tabController.animateTo(1);
                          }
                        },
                        child: Text(&#39;Submit&#39;),
                      ),
                    ],
                  ),
                ),

                Container(
                  color: Colors.green,
                ),
                Container(
                  color: Colors.blue,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
英文:

Flirty setting physics: const NeverScrollableScrollPhysics(), to disable the swap changes(mostly needed).

Then use the TabController to change the tab only on validation, Here is a demo example

class FTExample extends StatefulWidget {
  const FTExample({super.key});

  @override
  State&lt;FTExample&gt; createState() =&gt; _FTExampleState();
}

class _FTExampleState extends State&lt;FTExample&gt;
    with SingleTickerProviderStateMixin {
  final formKey = GlobalKey&lt;FormState&gt;();
  late final tabController = TabController(length: 3, vsync: this);

  @override
  Widget build(BuildContext context) {
    // tabbar
    return Scaffold(
      appBar: AppBar(
        title: const Text(&#39;TabBar&#39;),
      ),
      body: Column(
        children: [
          TabBar(
            controller: tabController,
            tabs: [
              Tab(
                icon: Icon(Icons.directions_car),
              ),
              Tab(
                icon: Icon(Icons.directions_transit),
              ),
              Tab(
                icon: Icon(Icons.directions_bike),
              ),
            ],
          ),
          Expanded(
            child: TabBarView(
              physics: const NeverScrollableScrollPhysics(), // you can use a bool to switch between NeverScrollableScrollPhysics and BouncingScrollPhysics
              controller: tabController,
              children: [
                //Form with a TextFiled and button
                Form(
                  key: formKey,
                  child: Column(
                    children: [
                      TextFormField(
                        validator: (value) {
                          if (value == null || value.isEmpty) {
                            return &#39;Please enter some text&#39;;
                          }
                          return null;
                        },
                        decoration: InputDecoration(
                          labelText: &#39;Name&#39;,
                          hintText: &#39;Enter your name&#39;,
                        ),
                      ),
                      ElevatedButton(
                        onPressed: () {
                          if (formKey.currentState?.validate() == true) {
                            tabController.animateTo(1);
                          }
                        },
                        child: Text(&#39;Submit&#39;),
                      ),
                    ],
                  ),
                ),

                Container(
                  color: Colors.green,
                ),
                Container(
                  color: Colors.blue,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

huangapple
  • 本文由 发表于 2023年4月13日 21:48:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76006238.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定