Skip to content

Commit

Permalink
feat: rounded rectangle page indicator and size transition (#831)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jupi007 authored Feb 17, 2024
1 parent 7a122dc commit e63ef64
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
29 changes: 27 additions & 2 deletions example/lib/pages/page_indicator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class _PageIndicatorPageState extends State<PageIndicatorPage> {

@override
Widget build(BuildContext context) {
const duration = Duration(milliseconds: 250);

return YaruScrollViewUndershoot.builder(
builder: (context, controller) {
return ListView(
Expand All @@ -37,7 +39,7 @@ class _PageIndicatorPageState extends State<PageIndicatorPage> {
size: Size.square(
index == selectedIndex ? _dotSize + 8 : _dotSize,
),
animationDuration: const Duration(milliseconds: 250),
animationDuration: duration,
),
),
const SizedBox(height: 15),
Expand All @@ -55,7 +57,30 @@ class _PageIndicatorPageState extends State<PageIndicatorPage> {
size: Size.square(
index <= selectedIndex ? _dotSize + 8 : _dotSize,
),
animationDuration: const Duration(milliseconds: 250),
animationDuration: duration,
),
),
const SizedBox(height: 20),
YaruPageIndicator.builder(
length: _length,
page: _page,
onTap: (page) => setState(() => _page = page),
itemSizeBuilder: (index, selectedIndex, length) =>
index == selectedIndex
? Size(_dotSize * 3, _dotSize)
: Size.square(_dotSize),
layoutDelegate: YaruPageIndicatorSteppedDelegate(
baseItemSpacing: _dotSpacing,
),
animationDuration: duration,
itemBuilder: (index, selectedIndex, length) =>
YaruPageIndicatorItem(
selected: index == selectedIndex,
size: index == selectedIndex
? Size(_dotSize * 3, _dotSize)
: Size.square(_dotSize),
animationDuration: duration,
borderRadius: BorderRadius.circular(24),
),
),
const SizedBox(height: 15),
Expand Down
45 changes: 43 additions & 2 deletions lib/src/widgets/yaru_page_indicator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class YaruPageIndicator extends StatelessWidget {
this.textStyle,
double? dotSize,
double? dotSpacing,
this.animationDuration,
this.animationCurve,
}) : assert(page >= 0 && page <= length - 1),
itemBuilder = null {
itemSizeBuilder =
Expand All @@ -57,6 +59,8 @@ class YaruPageIndicator extends StatelessWidget {
this.textBuilder,
this.textStyle,
this.layoutDelegate,
this.animationDuration,
this.animationCurve,
}) : assert(page >= 0 && page <= length - 1);

/// Determine the number of pages.
Expand Down Expand Up @@ -103,6 +107,17 @@ class YaruPageIndicator extends StatelessWidget {
/// Defaults to [YaruPageIndicatorSteppedDelegate].
late final YaruPageIndicatorLayoutDelegate? layoutDelegate;

/// Duration of a size transition between two items.
/// Use [Duration.zero] to disable transition.
///
/// Defaults to [Duration.zero].
final Duration? animationDuration;

/// Curve used in a size transition between two items.
///
/// Defaults to [Curves.linear].
final Curve? animationCurve;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
Expand Down Expand Up @@ -168,7 +183,7 @@ class YaruPageIndicator extends StatelessWidget {
padding: EdgeInsetsDirectional.only(
start: index != 0 ? itemSpacing : 0,
),
child: SizedBox(
child: _buildSizedContainer(
width: itemSizes[index].width,
height: itemSizes[index].height,
child: Center(
Expand All @@ -187,6 +202,28 @@ class YaruPageIndicator extends StatelessWidget {
},
);
}

Widget _buildSizedContainer({
required double width,
required double height,
required Widget child,
}) {
final animationDuration = this.animationDuration ?? Duration.zero;
final animationCurve = this.animationCurve ?? Curves.linear;
return animationDuration != Duration.zero
? AnimatedContainer(
duration: animationDuration,
curve: animationCurve,
width: width,
height: height,
child: child,
)
: SizedBox(
width: width,
height: height,
child: child,
);
}
}

/// Default item used in [YaruPageIndicator.itemBuilder].
Expand All @@ -200,6 +237,7 @@ class YaruPageIndicatorItem extends StatelessWidget {
this.size,
this.animationDuration,
this.animationCurve,
this.borderRadius,
});

/// Define if this is a selected item.
Expand All @@ -219,6 +257,8 @@ class YaruPageIndicatorItem extends StatelessWidget {
/// Defaults to [Curves.linear].
final Curve? animationCurve;

final BorderRadiusGeometry? borderRadius;

@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
Expand All @@ -227,7 +267,8 @@ class YaruPageIndicatorItem extends StatelessWidget {
color: selected
? theme.colorScheme.primary
: theme.colorScheme.onSurface.withOpacity(.3),
shape: BoxShape.circle,
shape: borderRadius == null ? BoxShape.circle : BoxShape.rectangle,
borderRadius: borderRadius,
);
final animationDuration = this.animationDuration ?? Duration.zero;
final animationCurve = this.animationCurve ?? Curves.linear;
Expand Down

0 comments on commit e63ef64

Please sign in to comment.