📜  如何在 Flutter Tabs 中添加圆点作为指示器? - 飞镖(1)

📅  最后修改于: 2023-12-03 14:52:17.463000             🧑  作者: Mango

如何在 Flutter Tabs 中添加圆点作为指示器? - 飞镖

在 Flutter 中使用 Tabs 是非常方便和常见的,但是默认的指示器可能不符合你的需求。本文将介绍如何在 Flutter Tabs 中添加圆点作为指示器。

准备工作

在开始之前,您需要先准备好一个带有 Tabs 的页面,例如:

class MyTabs extends StatefulWidget {
  @override
  _MyTabsState createState() => _MyTabsState();
}

class _MyTabsState extends State<MyTabs> with SingleTickerProviderStateMixin {
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        bottom: TabBar(
          controller: _tabController,
          tabs: [
            Tab(text: 'Tab 1'),
            Tab(text: 'Tab 2'),
            Tab(text: 'Tab 3'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          Container(color: Colors.red),
          Container(color: Colors.blue),
          Container(color: Colors.yellow),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }
}
添加圆点指示器

要将圆点添加到 Tabs 中,首先需要掌握的是:

  • TabBar 的 indicator 属性可以接受一个 Widget,用于自定义指示器。
  • TabBarView 的 onPageChanged 回调可以获取当前页面的索引。

利用这两个属性,我们可以很方便地添加圆点指示器。具体步骤如下:

1. 准备圆点 Widget
class DotIndicator extends Decoration {
  @override
  BoxPainter createBoxPainter([VoidCallback onChanged]) {
    return _DotBoxPainter();
  }
}

class _DotBoxPainter extends BoxPainter {
  static const double _radius = 3;
  static const double _dotSpacing = 5;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final size = configuration.size;
    final paint = Paint()..color = Colors.white;
    final center = offset + Offset(size.width/2, size.height/2);

    final maxRadius = _radius * 2;

    for (var i = 0; i < configuration.tabCount; i++) {
      var currentRadius = _radius;
      if (i == configuration.selectedIndex) {
        currentRadius = maxRadius;
      }

      final dx = -(configuration.tabCount * _radius * 2 + (configuration.tabCount - 1) * _dotSpacing) / 2 + i * (currentRadius * 2 + _dotSpacing);
      final offset = center.translate(dx, 0);
      canvas.drawCircle(offset, currentRadius, paint);
    }
  }
}

上述代码的作用是定义了一个继承自 Decoration 的圆点装饰器,其中 _DotBoxPainter 控制圆点的绘制。圆点的直径为 6,圆点之间的间隔为 5。在显示时,将会在当前 Tab 下方显示一个更大的圆点。

2. 在 TabBar 中设置 indicator
bottom: TabBar(
  controller: _tabController,
  indicator: DotIndicator(),
  tabs: [
    Tab(text: 'Tab 1'),
    Tab(text: 'Tab 2'),
    Tab(text: 'Tab 3'),
  ],
),

通过将 DotIndicator 作为 indicator 属性传递给 TabBar,可以将圆点指示器添加到 Tabs 中。

3. 监听 onPageChanged 事件
body: TabBarView(
  controller: _tabController,
  children: [
    Container(color: Colors.red),
    Container(color: Colors.blue),
    Container(color: Colors.yellow),
  ],
  onPageChanged: (index) {
    setState(() {
      _tabController.index = index;
    });
  },
),

为了保证圆点指示器在滑动 Tabs 时能够正确地显示,我们监听了 TabBarViewonPageChanged 事件,并在事件处理函数中手动设置了 TabController 的 index 属性。这样,当滑动到新的 Tab 时,TabController 会自动更新当前选择的 Tab,圆点指示器也能同步更新。

效果预览

完成以上步骤后,就可以在 Tabs 中添加圆点指示器了。效果如下:

圆点指示器效果预览

结论

通过本文,您已经掌握了如何在 Flutter Tabs 中添加圆点作为指示器的方法,希望对您有所帮助。完整代码如下:

class MyTabs extends StatefulWidget {
  @override
  _MyTabsState createState() => _MyTabsState();
}

class _MyTabsState extends State<MyTabs> with SingleTickerProviderStateMixin {
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        bottom: TabBar(
          controller: _tabController,
          indicator: DotIndicator(),
          tabs: [
            Tab(text: 'Tab 1'),
            Tab(text: 'Tab 2'),
            Tab(text: 'Tab 3'),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          Container(color: Colors.red),
          Container(color: Colors.blue),
          Container(color: Colors.yellow),
        ],
        onPageChanged: (index) {
          setState(() {
            _tabController.index = index;
          });
        },
      ),
    );
  }

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

class DotIndicator extends Decoration {
  @override
  BoxPainter createBoxPainter([VoidCallback onChanged]) {
    return _DotBoxPainter();
  }
}

class _DotBoxPainter extends BoxPainter {
  static const double _radius = 3;
  static const double _dotSpacing = 5;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final size = configuration.size;
    final paint = Paint()..color = Colors.white;
    final center = offset + Offset(size.width/2, size.height/2);

    final maxRadius = _radius * 2;

    for (var i = 0; i < configuration.tabCount; i++) {
      var currentRadius = _radius;
      if (i == configuration.selectedIndex) {
        currentRadius = maxRadius;
      }

      final dx = -(configuration.tabCount * _radius * 2 + (configuration.tabCount - 1) * _dotSpacing) / 2 + i * (currentRadius * 2 + _dotSpacing);
      final offset = center.translate(dx, 0);
      canvas.drawCircle(offset, currentRadius, paint);
    }
  }
}