边框中的颤动箭头

Flutter arrow in border

我想添加一个轻量级的导航栏来切换登录和注册。 结果应如下所示:

箭头应指示当前所选页面。

参考这个,问题中的UI与你的相似,答案中使用的概念可以根据你的需要进行调整。

这对我有用:

class TapBarDesign extends StatefulWidget {
  const TapBarDesign({Key? key}) : super(key: key);

  @override
  _TapBarDesignState createState() => _TapBarDesignState();
}

class _TapBarDesignState extends State<TapBarDesign>
    with SingleTickerProviderStateMixin {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        backgroundColor: Colors.blue,
        appBar: AppBar(
          toolbarHeight: 0,
          backgroundColor: Colors.transparent,
          elevation: 0,
          bottom: TabBar(
            indicatorSize: TabBarIndicatorSize.tab,
            indicator: ArrowTabBarIndicator(),
            tabs: const <Widget>[
              Tab(
                child: Text(
                  'Page 1',
                ),
              ),
              Tab(
                child: Text(
                  'Page 2',
                ),
              ),
            ],
          ),
        ),
        body: const TabBarView(
          children: <Widget>[
            Center(child: Text('Page 1')),
            Center(child: Text('Page 2')),
          ],
        ),
      ),
    );
  }
}

class ArrowTabBarIndicator extends Decoration {
  final BoxPainter _painter;

  ArrowTabBarIndicator({double width = 20, double height = 10})
      : _painter = _ArrowPainter(width, height);

  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) => _painter;
}

class _ArrowPainter extends BoxPainter {
  final Paint _paint;
  final double width;
  final double height;

  _ArrowPainter(this.width, this.height)
      : _paint = Paint()
          ..color = Colors.white
          ..strokeWidth = 1
          ..strokeCap = StrokeCap.round;

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
    const pointMode = ui.PointMode.polygon;

    if (cfg.size != null) {
      final points = [
        Offset(0, cfg.size!.height),
        Offset(cfg.size!.width / 2 - (width / 2), cfg.size!.height) + offset,
        Offset(cfg.size!.width / 2, (cfg.size!.height + height)) + offset,
        Offset(cfg.size!.width / 2 + (width / 2), cfg.size!.height) + offset,
        Offset(cfg.size!.width * 2, cfg.size!.height),
      ];
      canvas.drawPoints(pointMode, points, _paint);
    }
  }
}