You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
5.2 KiB
Dart
198 lines
5.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
|
|
class CarouselIndicator extends StatefulWidget {
|
|
/// width of the indicator
|
|
final double width;
|
|
|
|
/// height of the indicator
|
|
final double height;
|
|
|
|
/// space between indicators.
|
|
final double space;
|
|
|
|
/// count of indicator
|
|
final int count;
|
|
|
|
/// active color
|
|
final Color activeColor;
|
|
|
|
/// normal color
|
|
final Color color;
|
|
|
|
/// use this to give some radius to the corner indicator
|
|
final double cornerRadius;
|
|
|
|
/// duration for slide animation
|
|
final int animationDuration;
|
|
|
|
final int index;
|
|
|
|
final Function(int index) onClick;
|
|
|
|
CarouselIndicator({
|
|
Key key,
|
|
this.width: 20.0,
|
|
this.height: 6,
|
|
this.space: 5.0,
|
|
this.count,
|
|
this.cornerRadius: 6,
|
|
this.animationDuration: 300,
|
|
this.color: Colors.white30,
|
|
this.index,
|
|
this.activeColor: Colors.white,
|
|
this.onClick
|
|
}) : assert(count != null && count != 0),
|
|
assert(index != null && index >= 0),
|
|
super(key: key);
|
|
|
|
@override
|
|
State<StatefulWidget> createState() {
|
|
return new _CarouselIndicatorState();
|
|
}
|
|
}
|
|
|
|
class _CarouselIndicatorState extends State<CarouselIndicator>
|
|
with TickerProviderStateMixin {
|
|
/// [Tween] object of type double
|
|
Tween<double> _tween;
|
|
|
|
/// [AnimationController] object
|
|
AnimationController _animationController;
|
|
|
|
/// [Aniamtion] object
|
|
Animation _animation;
|
|
|
|
/// [Paint] object to paint our indicator
|
|
Paint _paint = new Paint();
|
|
|
|
/// Method to initilize [BasePainter] to paint indicators.
|
|
BasePainter _createPainer() {
|
|
return SlidePainter(widget, _animation.value, _paint);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget child = new SizedBox(
|
|
width: widget.count * widget.width + (widget.count - 1) * widget.space,
|
|
height: widget.height,
|
|
child: CustomPaint(
|
|
painter: _createPainer(),
|
|
),
|
|
);
|
|
|
|
return InkWell(
|
|
child: child,
|
|
onTap: (){
|
|
if(widget.onClick != null)
|
|
widget.onClick(0);
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
/// for initial index=0 we do not want to change any value so setting [_tween] to (0.0,0.0),
|
|
createAnimation(0.0, 0.0);
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void didUpdateWidget(CarouselIndicator oldWidget) {
|
|
if (widget.index != oldWidget.index) {
|
|
if (widget.index != 0) {
|
|
_animationController.reset();
|
|
|
|
/// for each new index we want to change value so setting [_tween] to (oldWidget.index,widget.index) so animation tween from old position to new position rather not start from 0.0 again and again.
|
|
createAnimation(oldWidget.index.toDouble(), widget.index.toDouble());
|
|
_animationController.forward();
|
|
} else {
|
|
_animationController.reset();
|
|
createAnimation(oldWidget.index.toDouble(), 0.0);
|
|
_animationController.forward();
|
|
}
|
|
}
|
|
super.didUpdateWidget(oldWidget);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_animationController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void createAnimation(double begin, double end) {
|
|
_tween = Tween(begin: begin, end: end);
|
|
_animationController = AnimationController(
|
|
vsync: this,
|
|
duration: Duration(milliseconds: widget.animationDuration));
|
|
_animation = _tween.animate(_animationController)
|
|
..addListener(() {
|
|
setState(() {});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
/// Base Painter class to draw indicator
|
|
abstract class BasePainter extends CustomPainter {
|
|
final CarouselIndicator widget;
|
|
final double page;
|
|
final Paint _paint;
|
|
|
|
BasePainter(this.widget, this.page, this._paint);
|
|
|
|
/// This method will get body to class extending [BasePainter] and this method will draw the sliding indicator which slide over changing index.
|
|
void draw(Canvas canvas, double space, double width, double height,
|
|
double radius, double cornerRadius);
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
_paint.color = widget.color;
|
|
double space = widget.space;
|
|
double width = widget.width;
|
|
double height = widget.height;
|
|
double distance = width + space;
|
|
double radius = width / 2;
|
|
for (int i = 0, c = widget.count; i < c; ++i) {
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(
|
|
Rect.fromCenter(
|
|
center: Offset((i * distance) + radius, radius),
|
|
width: width,
|
|
height: height),
|
|
Radius.circular(widget.cornerRadius)),
|
|
_paint);
|
|
}
|
|
|
|
_paint.color = widget.activeColor;
|
|
draw(canvas, space, width, height, radius, widget.cornerRadius);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(BasePainter oldDelegate) {
|
|
return oldDelegate.page != page;
|
|
}
|
|
}
|
|
|
|
/// This class we draw the indicator which slides.
|
|
class SlidePainter extends BasePainter {
|
|
SlidePainter(CarouselIndicator widget, double page, Paint paint)
|
|
: super(widget, page, paint);
|
|
|
|
@override
|
|
void draw(Canvas canvas, double space, double width, double height,
|
|
double radius, double cornerRadius) {
|
|
canvas.drawRRect(
|
|
RRect.fromRectAndRadius(
|
|
Rect.fromCenter(
|
|
center: Offset(radius + (page * (width + space)), radius),
|
|
width: width,
|
|
height: height),
|
|
Radius.circular(cornerRadius)),
|
|
_paint);
|
|
}
|
|
}
|
|
|