Skip to content

Commit

Permalink
[FEATURE] Support RTL
Browse files Browse the repository at this point in the history
  • Loading branch information
therezacuet committed Dec 12, 2023
1 parent a329a3b commit d9fae8b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 63 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Motion Tab Bar compatible with Flutter 3
# Motion Tab Bar compatible with Flutter 3 and RTL support

[![pub package](https://img.shields.io/pub/v/motion_tab_bar)](https://pub.dev/packages/motion_tab_bar)
[![likes](https://img.shields.io/pub/likes/motion_tab_bar)](https://pub.dev/packages/motion_tab_bar/score)
Expand All @@ -19,7 +19,7 @@ Add the plugin:

```yaml
dependencies:
motion_tab_bar: ^2.0.2
motion_tab_bar: ^2.0.3
```
## Basic Usage
Expand Down
130 changes: 70 additions & 60 deletions lib/MotionTabBar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ class _MotionTabBarState extends State<MotionTabBar> with TickerProviderStateMix

get tabAmount => icons.keys.length;
get index => labels.indexOf(selectedTab);
get position {
double pace = 2 / (labels.length - 1);
return (pace * index) - 1;
}

double fabIconAlpha = 1;
IconData? activeIcon;
Expand All @@ -74,76 +70,89 @@ class _MotionTabBarState extends State<MotionTabBar> with TickerProviderStateMix
List<Widget>? badges;
Widget? activeBadge;

@override
void initState() {
super.initState();
double getPosition(bool isRTL) {
double pace = 2 / (labels.length - 1);
double position = (pace * index) - 1;

if(widget.controller != null) {
widget.controller!.onTabChange= (index) {
setState(() {
activeIcon = widget.icons![index];
selectedTab = widget.labels[index];
});
_initAnimationAndStart(_positionAnimation.value, position);
};
if (isRTL) {
// If RTL, reverse the position calculation
position = 1 - (pace * index);
}

labels = widget.labels;
icons = Map.fromIterable(
labels,
key: (label) => label,
value: (label) => widget.icons![labels.indexOf(label)],
);
return position;
}

@override
void initState() {
super.initState();

selectedTab = widget.initialSelectedTab;
activeIcon = icons[selectedTab];
WidgetsBinding.instance.addPostFrameCallback((_) async {
bool isRtl = Directionality.of(context).index == 0;
if(widget.controller != null) {
widget.controller!.onTabChange= (index) {
setState(() {
activeIcon = widget.icons![index];
selectedTab = widget.labels[index];
});
_initAnimationAndStart(_positionAnimation.value, getPosition(isRtl));
};
}
labels = widget.labels;
icons = Map.fromIterable(
labels,
key: (label) => label,
value: (label) => widget.icons![labels.indexOf(label)],
);

// init badge text
int selectedIndex = labels.indexWhere((element) => element == widget.initialSelectedTab);
activeBadge = (widget.badges != null && widget.badges!.length > 0) ? widget.badges![selectedIndex] : null;
selectedTab = widget.initialSelectedTab;
activeIcon = icons[selectedTab];

_animationController = AnimationController(
duration: Duration(milliseconds: ANIM_DURATION),
vsync: this,
);
// init badge text
int selectedIndex = labels.indexWhere((element) => element == widget.initialSelectedTab);
activeBadge = (widget.badges != null && widget.badges!.length > 0) ? widget.badges![selectedIndex] : null;

_fadeOutController = AnimationController(
duration: Duration(milliseconds: (ANIM_DURATION ~/ 5)),
vsync: this,
);
_animationController = AnimationController(
duration: Duration(milliseconds: ANIM_DURATION),
vsync: this,
);

_positionTween = Tween<double>(begin: position, end: 1);
_fadeOutController = AnimationController(
duration: Duration(milliseconds: (ANIM_DURATION ~/ 5)),
vsync: this,
);

_positionAnimation = _positionTween.animate(CurvedAnimation(parent: _animationController, curve: Curves.easeOut))
..addListener(() {
setState(() {});
});
_positionTween = Tween<double>(begin: getPosition(isRtl), end: 1);

_fadeFabOutAnimation = Tween<double>(begin: 1, end: 0)
.animate(CurvedAnimation(parent: _fadeOutController, curve: Curves.easeOut))
..addListener(() {
setState(() {
fabIconAlpha = _fadeFabOutAnimation.value;
_positionAnimation = _positionTween.animate(CurvedAnimation(parent: _animationController, curve: Curves.easeOut))
..addListener(() {
setState(() {});
});
})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {

_fadeFabOutAnimation = Tween<double>(begin: 1, end: 0)
.animate(CurvedAnimation(parent: _fadeOutController, curve: Curves.easeOut))
..addListener(() {
setState(() {
activeIcon = icons[selectedTab];
fabIconAlpha = _fadeFabOutAnimation.value;
});
})
..addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {
activeIcon = icons[selectedTab];
int selectedIndex = labels.indexWhere((element) => element == selectedTab);
activeBadge = (widget.badges != null && widget.badges!.length > 0) ? widget.badges![selectedIndex] : null;
});
}
});

int selectedIndex = labels.indexWhere((element) => element == selectedTab);
activeBadge = (widget.badges != null && widget.badges!.length > 0) ? widget.badges![selectedIndex] : null;
_fadeFabInAnimation = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(parent: _animationController, curve: Interval(0.8, 1, curve: Curves.easeOut)))
..addListener(() {
setState(() {
fabIconAlpha = _fadeFabInAnimation.value;
});
}
});

_fadeFabInAnimation = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(parent: _animationController, curve: Interval(0.8, 1, curve: Curves.easeOut)))
..addListener(() {
setState(() {
fabIconAlpha = _fadeFabInAnimation.value;
});
});
});
}

@override
Expand Down Expand Up @@ -262,6 +271,7 @@ class _MotionTabBarState extends State<MotionTabBar> with TickerProviderStateMix
}

List<Widget> generateTabItems() {
bool isRtl = Directionality.of(context).index == 0;
return labels.map((tabLabel) {
IconData? icon = icons[tabLabel];

Expand All @@ -282,7 +292,7 @@ class _MotionTabBarState extends State<MotionTabBar> with TickerProviderStateMix
selectedTab = tabLabel;
widget.onTabItemSelected!(index);
});
_initAnimationAndStart(_positionAnimation.value, position);
_initAnimationAndStart(_positionAnimation.value, getPosition(isRtl));
},
);
}).toList();
Expand Down
Binary file modified motiontabbar_v2.1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified motiontabbar_v2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: motion_tab_bar
description: An animated Bottom Navigation Bar for Flutter apps, icon animates into place, colors are customizable.
version: 2.0.2
version: 2.0.3
homepage: https://github.com/therezacuet/Motion-Tab-Bar

environment:
Expand Down

0 comments on commit d9fae8b

Please sign in to comment.