Reputation: 23
How I can make the cursor of tab bar with an arrow
like this?
Upvotes: 2
Views: 1409
Reputation: 325
Null Safety Code for the answer:
class CircleTabIndicator extends Decoration {
final BoxPainter _painter;
CircleTabIndicator({required Color color}) : _painter = _CirclePainter(color);
@override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
return _painter;
}
}
class _CirclePainter extends BoxPainter {
final Paint _paint;
_CirclePainter(Color color)
: _paint = Paint()
..color = color
..isAntiAlias = true;
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
Path trianglePath = Path();
trianglePath.moveTo(cfg.size!.width / 2 - 10, cfg.size!.height);
trianglePath.lineTo(cfg.size!.width / 2 + 10, cfg.size!.height);
trianglePath.lineTo(cfg.size!.width / 2, cfg.size!.height - 10);
trianglePath.lineTo(cfg.size!.width / 2 - 10, cfg.size!.height);
trianglePath.close();
canvas.drawPath(trianglePath, _paint);
}
}
Upvotes: 0
Reputation: 2321
Building on Virens' answer I've made this version of the painter which addresses the issues in the comments and is null safe for use with newer versions of Flutter.
It may also serve to more clearly illustrate what's going on in the paint method.
import 'package:flutter/material.dart';
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
..isAntiAlias = true;
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
Path _trianglePath = Path();
if (cfg.size != null){
Offset centerTop = Offset(cfg.size!.width / 2, cfg.size!.height - height) + offset;
Offset bottomLeft = Offset(cfg.size!.width / 2 - (width/2), cfg.size!.height) + offset;
Offset bottomRight = Offset(cfg.size!.width / 2 + (width/2), cfg.size!.height) + offset;
_trianglePath.moveTo(bottomLeft.dx, bottomLeft.dy);
_trianglePath.lineTo(bottomRight.dx, bottomRight.dy);
_trianglePath.lineTo(centerTop.dx, centerTop.dy);
_trianglePath.lineTo(bottomLeft.dx, bottomLeft.dy);
_trianglePath.close();
canvas.drawPath(_trianglePath, _paint);
}
}
}
The main issue with the original answer was that it didn't take into account the 'offset' parameter which controls in this case which tab the indicator is drawn under.
Upvotes: 1
Reputation: 27177
You can achieve your desire indicator using custom painter and tabindicator.
import 'package:flutter/material.dart';
class Delete extends StatefulWidget {
Delete({Key key}) : super(key: key);
@override
_DeleteState createState() => _DeleteState();
}
class _DeleteState extends State<Delete> with SingleTickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
indicatorSize: TabBarIndicatorSize.tab,
indicator: CircleTabIndicator(color: Colors.orange),
tabs: <Widget>[
Tab(
child: Text(
'fruits',
),
),
Tab(
child: Text(
'vegetables',
),
),
Tab(
child: Text(
'berries',
),
),
],
),
),
body: TabBarView(
children: <Widget>[
Center(child: Text('Tab 1')),
Center(child: Text('Tab 2')),
Center(child: Text('Tab 3')),
],
),
),
);
}
}
class CircleTabIndicator extends Decoration {
final BoxPainter _painter;
CircleTabIndicator({@required Color color})
: _painter = _CirclePainter(color);
@override
BoxPainter createBoxPainter([onChanged]) => _painter;
}
class _CirclePainter extends BoxPainter {
final Paint _paint;
_CirclePainter(Color color)
: _paint = Paint()
..color = color
..isAntiAlias = true;
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration cfg) {
Path _trianglePath = Path();
_trianglePath.moveTo(cfg.size.width / 2 - 10, cfg.size.height);
_trianglePath.lineTo(cfg.size.width / 2 + 10, cfg.size.height);
_trianglePath.lineTo(cfg.size.width / 2, cfg.size.height - 10);
_trianglePath.lineTo(cfg.size.width / 2 - 10, cfg.size.height);
_trianglePath.close();
canvas.drawPath(_trianglePath, _paint);
}
}
Upvotes: 1