Flutter之TabBar篇

總結(jié)了一下項(xiàng)目中用到的幾種TabBar,針對(duì)不同的樣式诵原,有采用系統(tǒng)提供的英妓,也有三方插件提供的,也有自定義的绍赛,效果如下(后續(xù)如果遇到新的樣式蔓纠,會(huì)不間斷地記錄更新,避免重復(fù)造輪子....)

gif.gif

用到的三方插件:

buttons_tabbar: ^1.3.8
flutter_easyloading: ^3.0.5

1吗蚌、先看第一種系統(tǒng)的

image.png

代碼如下:

class CustomTabBar extends StatelessWidget {
  final TabController tabController;
  final List<String> tabs;
  final TextStyle labelStyle;
  final Color labelColor;
  final Color unselectedLabelColor;
  final TextStyle unselectedLabelStyle;
  final Color indicatorColor;
  final double indicatorWeight;
  const CustomTabBar({
    super.key,
    required this.tabController,
    required this.tabs,
    this.labelStyle = const TextStyle(
      fontSize: 16.0,
      fontWeight: FontWeight.w700,
    ),
    this.labelColor = Colors.blue,
    this.unselectedLabelColor = Colors.red,
    this.unselectedLabelStyle = const TextStyle(
      fontSize: 16.0,
      fontWeight: FontWeight.w400,
    ),
    this.indicatorColor = Colors.blue,
    this.indicatorWeight = 5.0,
  });

  @override
  Widget build(BuildContext context) {
    return TabBar(
      controller: tabController,
      tabs: tabs.map((e) => Tab(text: e)).toList(),
      isScrollable: true,
      labelPadding: const EdgeInsets.symmetric(horizontal: 16.0),
      labelStyle: labelStyle,
      labelColor: labelColor,
      unselectedLabelColor: unselectedLabelColor,
      unselectedLabelStyle: unselectedLabelStyle,
      indicatorWeight: indicatorWeight,
      indicator: DotTabIndicator(
        color: indicatorColor,
        radius: 4,
      ),
      onTap: (value) {},
      dividerColor: Colors.transparent, //去除tabBar下面的那根線的顏色
    );
  }
}

class DotTabIndicator extends Decoration {
  final Color color;
  final double radius;

  const DotTabIndicator({required this.color, required this.radius});

  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    return _DotTabIndicatorPainter(this, onChanged!);
  }
}

class _DotTabIndicatorPainter extends BoxPainter {
  final DotTabIndicator decoration;

  _DotTabIndicatorPainter(this.decoration, VoidCallback onChanged)
      : super(onChanged);

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final Rect rect = offset & configuration.size!;
    final Paint paint = Paint();
    paint.color = decoration.color;
    paint.style = PaintingStyle.fill;
    final Offset circleOffset =
        Offset(rect.center.dx, rect.bottomCenter.dy - decoration.radius);
    canvas.drawCircle(circleOffset, decoration.radius, paint);
  }
}

使用方法:

late final TabController _tabController;
final List<String> _tabs = [
    "能源洞察",
    "用戶故事",
    "智匯回答",
  ];
  final List<Widget> _tabViews = [
    Container(color: Colors.red),
    Container(color: Colors.yellow),
    Container(color: Colors.orange),
  ];
@override
  void initState() {
    super.initState();
    _tabController = TabController(
      initialIndex: 1,
      length: _tabs.length,
      vsync: this,
    );
  }

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

Container(
            height: 200,
            child: Column(
              children: [
                CustomTabBar(
                  tabController: _tabController,
                  indicatorWeight: 1,
                  tabs: _tabs,
                ),
                const SizedBox(height: 10.0),
                Expanded(
                  child: TabBarView(
                    controller: _tabController,
                    children: _tabViews,
                  ),
                ),
              ],
            ),
          ),

第二種采用的三方插件buttons_tabbar: ^1.3.8

image.png

代碼如下:


  late final TabController _tabController;
  final List<String> _tabs = [
    "能源洞察",
    "用戶故事",
    "智匯回答",
  ];
  final List<Widget> _tabViews = [
    Container(color: Colors.red),
    Container(color: Colors.yellow),
    Container(color: Colors.orange),
  ];
@override
  void initState() {
    super.initState();
    _tabController = TabController(
      initialIndex: 0,
      length: _tabs.length,
      vsync: this,
    );
  }

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

SizedBox(
            height: 200,
            child: Column(
              children: [
                SizedBox(
                  height: 32.0,
                  child: ButtonsTabBar(
                    tabs: _tabs.map((e) => Tab(text: e)).toList(),
                    controller: _tabController,
                    backgroundColor: Colors.blue,
                    unselectedBackgroundColor: Colors.red,
                    labelStyle: const TextStyle(color: Colors.white),
                    unselectedLabelStyle: const TextStyle(color: Colors.black),
                    buttonMargin: const EdgeInsets.only(right: 35),
                    contentPadding:
                        const EdgeInsets.symmetric(horizontal: 15.0),
                    radius: 18,
                  ),
                ),
                const SizedBox(height: 10.0),
                Expanded(
                  child: TabBarView(
                    controller: _tabController,
                    children: _tabViews,
                  ),
                ),
              ],
            ),
          ),

第三種自定義

image.png

代碼如下:

class ButtonContainer extends StatelessWidget {
  final int containerIndex;
  final ValueChanged<int> onContainerSelected;
  final bool isSelected;
  final List data;
  final Color backgroundColor;
  final Color unBackgroundColor;
  final TextStyle labelStyle;
  final TextStyle unLabelStyle;
  const ButtonContainer({
    super.key,
    required this.containerIndex,
    required this.onContainerSelected,
    required this.isSelected,
    required this.data,
    this.backgroundColor = Colors.grey,
    this.unBackgroundColor = Colors.red,
    this.labelStyle = const TextStyle(
      color: Colors.black,
      fontSize: 16,
    ),
    this.unLabelStyle = const TextStyle(
      color: Colors.white,
      fontSize: 16,
    ),
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        onContainerSelected(containerIndex);
      },
      child: Container(
        padding: const EdgeInsets.all(8.0),
        margin: const EdgeInsets.all(10),
        decoration: BoxDecoration(
          color: isSelected ? backgroundColor : unBackgroundColor,
          borderRadius: BorderRadius.circular(8.0),
        ),
        child: Text(
          data[containerIndex],
          style: isSelected ? labelStyle : unLabelStyle,
        ),
      ),
    );
  }
}

使用方法:

int selectedContainerIndex = 4; //默認(rèn)選中第幾個(gè)
final List<String> dataList = [
    "能源",
    "用戶故事",
    "智回答",
    "能洞察",
    "用戶故事",
    "智匯答",
  ];
  Wrap(
              children: List.generate(dataList.length, (index) {
                return ButtonContainer(
                  containerIndex: index,
                  onContainerSelected: (index) {
                    setState(() {
                      // 更新選中狀態(tài)
                      selectedContainerIndex = index;
                    });
                    EasyLoading.showToast("Click---${dataList[index]}");
                  },
                  isSelected: index == selectedContainerIndex,
                  data: dataList,
                );
              }),
            ),

代碼已經(jīng)都貼出來(lái)了腿倚,大方向已經(jīng)指出標(biāo)明,至于根據(jù)項(xiàng)目需求更改其中的細(xì)枝末節(jié)就需要自行動(dòng)手了蚯妇,有不懂的可以在下方留言敷燎,看到會(huì)及時(shí)回復(fù)??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暂筝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子硬贯,更是在濱河造成了極大的恐慌焕襟,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饭豹,死亡現(xiàn)場(chǎng)離奇詭異鸵赖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拄衰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)它褪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人翘悉,你說(shuō)我怎么就攤上這事茫打。” “怎么了镐确?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵包吝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我源葫,道長(zhǎng)诗越,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任息堂,我火速辦了婚禮嚷狞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荣堰。我一直安慰自己床未,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布振坚。 她就那樣靜靜地躺著薇搁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渡八。 梳的紋絲不亂的頭發(fā)上啃洋,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音屎鳍,去河邊找鬼宏娄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛逮壁,可吹牛的內(nèi)容都是我干的孵坚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼卖宠!你這毒婦竟也來(lái)了巍杈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤逗堵,失蹤者是張志新(化名)和其女友劉穎秉氧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蜒秤,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汁咏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了作媚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攘滩。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖纸泡,靈堂內(nèi)的尸體忽然破棺而出漂问,到底是詐尸還是另有隱情女揭,我是刑警寧澤蚤假,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布吧兔,位于F島的核電站,受9級(jí)特大地震影響境蔼,放射性物質(zhì)發(fā)生泄漏灶平。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一箍土、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吴藻,春花似錦、人聲如沸沟堡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弦叶。三九已至,卻和暖如春妇多,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背立莉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜓耻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓饶氏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親有勾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容