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
late Tween < double > _tween ;
/// [AnimationController] object
late AnimationController _animationController ;
/// [Aniamtion] object
late 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 ) ;
}
}