【问题标题】:Flutter - How to make a custom TabBarFlutter - 如何制作自定义 TabBar
【发布时间】:2020-11-28 12:23:46
【问题描述】:

这是我想要的输出。我还是新手,所以任何人都可以让我知道是否已经有这种开关的小部件或者我应该如何制作一个? 另外,如果我选择另一个按钮,我希望此按钮下方显示的数据发生变化,但我想这很明显。

提前致谢。

【问题讨论】:

    标签: flutter dart flutter-layout


    【解决方案1】:

    如果你想要这样的标签布局,你可以使用这个

    输出:

    import 'package:flutter/material.dart';
    import 'package:icons_helper/icons_helper.dart';
    
    class DetailScreen extends StatefulWidget {
      var body;
      String title = "";
    
      DetailScreen(this.body, this.title);
    
      @override
      _MainPageState createState() => _MainPageState();
    }
    
    class _MainPageState extends State<DetailScreen> with TickerProviderStateMixin {
      late int _startingTabCount;
    
      List<Tab> _tabs = <Tab>[];
      List<Widget> _generalWidgets = <Widget>[];
      late TabController _tabController;
    
      @override
      void initState() {
        _startingTabCount = widget.body["related_modules"].length;
        _tabs = getTabs(_startingTabCount);
        _tabController = getTabController();
        super.initState();
      }
    
      @override
      void dispose() {
        _tabController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
            bottom: TabBar(
              isScrollable: true,
              tabs: _tabs,
              controller: _tabController,
            ),
            flexibleSpace: Container(
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: [
                    Colors.grey,
                    Colors.blue,
                  ],
                  stops: [0.3, 1.0],
                ),
              ),
            ),
            leading: IconButton(
              icon: Icon(Icons.arrow_back_ios),
              color: Colors.white,
              onPressed: () {
                Navigator.of(context, rootNavigator: true).pop(context);
              },
            ),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.skip_previous),
                color: Colors.white,
                onPressed: () {
                  goToPreviousPage();
                },
              ),
              Container(
                margin: EdgeInsets.only(right: 15),
                child: IconButton(
                  icon: Icon(Icons.skip_next),
                  color: Colors.white,
                  onPressed: () {
                    goToNextPage();
                  },
                ),
              )
            ],
          ),
          body: Column(
            children: <Widget>[
              Expanded(
                child: TabBarView(
                  physics: NeverScrollableScrollPhysics(),
                  controller: _tabController,
                  children: getWidgets(),
                ),
              ),
            ],
          ),
        );
      }
    
      TabController getTabController() {
        return TabController(length: _tabs.length, vsync: this)
          ..addListener(_updatePage);
      }
    
      Tab getTab(int widgetNumber) {
        return Tab(
          icon: Column(
            children: [
              if (widget.body["related_modules"][widgetNumber]["icon"].toString() ==
                  "fa-comments-o") ...[
                Icon(
                  Icons.comment_outlined,
                ),
              ] else if (widget.body["related_modules"][widgetNumber]["icon"]
                      .toString() ==
                  "fa-map-marker") ...[
                Icon(
                  Icons.location_on_rounded,
                ),
              ] else if (widget.body["related_modules"][widgetNumber]["icon"]
                      .toString() ==
                  "fa-address-card") ...[
                Icon(
                  Icons.contact_page_sharp,
                ),
              ] else ...[
                Icon(
                  getIconUsingPrefix(
                    name: widget.body["related_modules"][widgetNumber]["icon"]
                        .toString()
                        .substring(3),
                  ),
                )
              ]
            ],
          ),
          text: widget.body["related_modules"][widgetNumber]["label"].toString(),
        );
      }
    
      Widget getWidget(int widgetNumber) {
        return Center(
          child: Text("Widget nr: $widgetNumber"),
        );
      }
    
      List<Tab> getTabs(int count) {
        _tabs.clear();
        for (int i = 0; i < count; i++) {
          _tabs.add(getTab(i));
        }
        return _tabs;
      }
    
      List<Widget> getWidgets() {
        _generalWidgets.clear();
        for (int i = 0; i < _tabs.length; i++) {
          _generalWidgets.add(getWidget(i));
        }
        return _generalWidgets;
      }
    
      void _updatePage() {
        setState(() {});
      }
    
      //Tab helpers
    
      bool isFirstPage() {
        return _tabController.index == 0;
      }
    
      bool isLastPage() {
        return _tabController.index == _tabController.length - 1;
      }
    
      void goToPreviousPage() {
        _tabController.animateTo(_tabController.index - 1);
      }
    
      void goToNextPage() {
        isLastPage()
            ? showDialog(
                context: context,
                builder: (context) => AlertDialog(
                    title: Text("End reached"),
                    content: Text("This is the last page.")))
            : _tabController.animateTo(_tabController.index + 1);
      }
    }
    

    【讨论】:

      【解决方案2】:

      您也可以使用 PageView 小部件。

      const double borderRadius = 25.0;
      
      class CustomSwitchState extends StatefulWidget {
        @override
        _CustomSwitchStateState createState() => _CustomSwitchStateState();
      }
      
      class _CustomSwitchStateState extends State<CustomSwitchState> with SingleTickerProviderStateMixin {
      
        PageController _pageController;
        int activePageIndex = 0;
      
        @override
        void dispose() {
          _pageController.dispose();
          super.dispose();
        }
      
        @override
        void initState() {
          super.initState();
          _pageController = PageController();
        }
      
        @override
        Widget build(BuildContext context) {
          return Scaffold(
              body: SingleChildScrollView(
                physics: const ClampingScrollPhysics(),
                child: GestureDetector(
                  onTap: () {
                    FocusScope.of(context).requestFocus(FocusNode());
                  },
                  child: Container(
                    width: MediaQuery.of(context).size.width,
                    height: MediaQuery.of(context).size.height,
                    child: Column(
                      mainAxisSize: MainAxisSize.max,
                      children: <Widget>[
                        Padding(
                          padding: const EdgeInsets.only(top: 20.0),
                          child: _menuBar(context),
                        ),
                        Expanded(
                          flex: 2,
                          child: PageView(
                            controller: _pageController,
                            physics: const ClampingScrollPhysics(),
                            onPageChanged: (int i) {
                              FocusScope.of(context).requestFocus(FocusNode());
                              setState(() {
                                activePageIndex = i;
                              });
                            },
                            children: <Widget>[
                              ConstrainedBox(
                                constraints: const BoxConstraints.expand(),
                                child: Center(child: Text("Place Bid"),),
                              ),
                              ConstrainedBox(
                                constraints: const BoxConstraints.expand(),
                                child: Center(child: Text("Buy Now"),),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ));
        }
      
        Widget _menuBar(BuildContext context) {
          return Container(
            width: 300.0,
            height: 50.0,
            decoration: const BoxDecoration(
              color: Color(0XFFE0E0E0),
              borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
            ),
            child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Expanded(
                    child: InkWell(
                      borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
                      onTap: _onPlaceBidButtonPress,
                      child: Container(
                        width: MediaQuery.of(context).size.width,
                        padding: EdgeInsets.symmetric(vertical: 15),
                        alignment: Alignment.center,
                        decoration: (activePageIndex == 0) ? const BoxDecoration(
                          color: Colors.green,
                          borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
                        ) : null,
                        child: Text(
                          "Place Bid",
                          style: (activePageIndex == 0) ? TextStyle(color: Colors.white) : TextStyle(color: Colors.black),
                        ),
                      ),
                    ),
                  ),
                  Expanded(
                    child: InkWell(
                      borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
                      onTap: _onBuyNowButtonPress,
                      child: Container(
                        width: MediaQuery.of(context).size.width,
                        padding: EdgeInsets.symmetric(vertical: 15),
                        alignment: Alignment.center,
                        decoration: (activePageIndex == 1) ? const BoxDecoration(
                          color: Colors.green,
                          borderRadius: BorderRadius.all(Radius.circular(borderRadius)),
                        ) : null,
                        child: Text(
                          "Buy Now",
                          style: (activePageIndex == 1) ? TextStyle(color: Colors.white, fontWeight: FontWeight.bold) : TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
          );
        }
      
        void _onPlaceBidButtonPress() {
          _pageController.animateToPage(0,
              duration: const Duration(milliseconds: 500), curve: Curves.decelerate);
        }
      
        void _onBuyNowButtonPress() {
          _pageController.animateToPage(1,
              duration: const Duration(milliseconds: 500), curve: Curves.decelerate);
        }
      
      }
      

      输出

      【讨论】:

        【解决方案3】:

        您可以使用TabBar 小部件来实现此目的。我添加了一个完整的示例来演示如何使用 TabBar 小部件创建它:

        代码

        class StackOver extends StatefulWidget {
          @override
          _StackOverState createState() => _StackOverState();
        }
        
        class _StackOverState extends State<StackOver>
            with SingleTickerProviderStateMixin {
          TabController _tabController;
        
          @override
          void initState() {
            _tabController = TabController(length: 2, vsync: this);
            super.initState();
          }
        
          @override
          void dispose() {
            super.dispose();
            _tabController.dispose();
          }
        
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              appBar: AppBar(
                title: Text(
                  'Tab bar',
                ),
              ),
              body: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  children: [
                    // give the tab bar a height [can change hheight to preferred height]
                    Container(
                      height: 45,
                      decoration: BoxDecoration(
                        color: Colors.grey[300],
                        borderRadius: BorderRadius.circular(
                          25.0,
                        ),
                      ),
                      child: TabBar(
                        controller: _tabController,
                        // give the indicator a decoration (color and border radius)
                        indicator: BoxDecoration(
                          borderRadius: BorderRadius.circular(
                            25.0,
                          ),
                          color: Colors.green,
                        ),
                        labelColor: Colors.white,
                        unselectedLabelColor: Colors.black,
                        tabs: [
                          // first tab [you can add an icon using the icon property]
                          Tab(
                            text: 'Place Bid',
                          ),
        
                          // second tab [you can add an icon using the icon property]
                          Tab(
                            text: 'Buy Now',
                          ),
                        ],
                      ),
                    ),
                    // tab bar view here
                    Expanded(
                      child: TabBarView(
                        controller: _tabController,
                        children: [
                          // first tab bar view widget 
                          Center(
                            child: Text(
                              'Place Bid',
                              style: TextStyle(
                                fontSize: 25,
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                          ),
        
                          // second tab bar view widget
                          Center(
                            child: Text(
                              'Buy Now',
                              style: TextStyle(
                                fontSize: 25,
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            );
          }
        }
        

        输出

        【讨论】:

        • 自定义指示器和选项卡以这种方式工作,但是当我悬停或按下选项卡时,“墨水飞溅”效果仍然具有矩形形状(没有圆角),因为我正在使用 MaterialApp 的脚手架.你知道如何解决这个问题吗?
        【解决方案4】:

        试试这个你必须change一些colourfont:-

        import 'package:flutter/material.dart';
        
        typedef SwitchOnChange = Function(int);
        
        class CustomSwitch extends StatefulWidget {
          SwitchOnChange onChange;
        
          CustomSwitch({this.onChange});
        
          @override
          State<StatefulWidget> createState() {
            return CustomSwitchState();
          }
        }
        
        class CustomSwitchState extends State<CustomSwitch>
            with TickerProviderStateMixin {
          AnimationController controller;
          Animation animation;
        
          GlobalKey key = GlobalKey();
          @override
          void initState() {
            Future.delayed(Duration(milliseconds: 100)).then((v) {
              controller = AnimationController(
                  vsync: this, duration: Duration(milliseconds: 300));
        
              tabWidth = key.currentContext.size.width / 2;
              // var width = (media.size.width - (2 * media.padding.left)) / 2;
              animation = Tween<double>(begin: 0, end: tabWidth).animate(controller);
        
              setState(() {});
        
              controller.addListener(() {
                setState(() {});
              });
            });
            super.initState();
          }
        
          var selectedValue = 0;
          double tabWidth = 0;
          @override
          Widget build(BuildContext context) {
            return GestureDetector(
              onTap: () {
                selectedValue == 0 ? this.controller.forward() : controller.reverse();
                selectedValue = selectedValue == 0 ? 1 : 0;
              },
              child: Container(
                key: key,
                height: 44,
                decoration: BoxDecoration(
                    color: Colors.grey, borderRadius: BorderRadius.circular(22)),
                child: Stack(
                  children: <Widget>[
                    Row(
                      children: <Widget>[
                        Transform.translate(
                          offset: Offset(animation?.value ?? 0, 0),
                          child: Container(
                            height: 44,
                            width: tabWidth,
                            decoration: BoxDecoration(
                                color: Colors.white,
                                borderRadius: BorderRadius.circular(22),
                                boxShadow: [
                                  BoxShadow(color: Colors.grey, blurRadius: 3),
                                ]),
                          ),
                        ),
                      ],
                    ),
                    Center(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: <Widget>[
                          Container(
                            width: tabWidth,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[
                                Icon(Icons.directions_walk),
                                SizedBox(width: 5),
                                Text("Place Bid")
                              ],
                            ),
                          ),
                          Container(
                            width: tabWidth,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: <Widget>[
                                Icon(Icons.directions_walk),
                                SizedBox(width: 5),
                                Text("Buy now")
                              ],
                            ),
                          )
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            );
          }
        }
        

        【讨论】:

        • 不需要处理吗?
        猜你喜欢
        • 1970-01-01
        • 2019-11-24
        • 2020-12-31
        • 1970-01-01
        • 1970-01-01
        • 2020-11-23
        • 1970-01-01
        • 2020-10-02
        • 2022-11-29
        相关资源
        最近更新 更多