Skip to content

Instantly share code, notes, and snippets.

@roipeker
Last active November 7, 2018 02:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roipeker/66bb7a0565df24336e3c748d98d5c28f to your computer and use it in GitHub Desktop.
Save roipeker/66bb7a0565df24336e3c748d98d5c28f to your computer and use it in GitHub Desktop.
Custom TabBar for Feathers
// =================================================================================================
//
// Created by Rodrigo Lopez [roipeker™] on 06/11/2018.
//
// =================================================================================================
package {
import feathers.controls.TabBar;
import feathers.controls.ToggleButton;
import flash.geom.Rectangle;
import starling.animation.Transitions;
import starling.core.Starling;
import starling.display.DisplayObject;
import starling.display.Quad;
public class AnimatedTabBar extends TabBar {
// helper Rectangle.
private var rect:Rectangle = new Rectangle();
private var _bar:Quad;
private var _bg:Quad;
// set to ::specialAnimation or ::simpleAnimation.
// null for no animation.
public var animationFunction:Function = specialAnimation;
public function AnimatedTabBar() {
super();
}
override protected function initialize():void {
super.initialize();
_bg = new Quad(4, 4, 0x444444);
_bar = new Quad(4, 2, 0xffffff);
_bar.visible = false;
addChild(_bg);
addChild(_bar);
if (_selectedIndex != -1) {
// 1 frame delay, waiting feathers to finish tabs UI invalidation.
Starling.juggler.delayCall( showSelected, 0, false );
}
}
override protected function refreshTabs(isFactoryInvalid:Boolean):void {
super.refreshTabs(isFactoryInvalid);
addChild(_bar);
}
override protected function draw():void {
super.draw();
if (isInvalid(INVALIDATION_FLAG_SIZE)) {
_bg.readjustSize(actualWidth, actualHeight);
_bar.y = actualHeight - _bar.height - 2;
}
}
override protected function commitSelection():void {
super.commitSelection();
// this will be called before the delay, but the tab will have no children built,
// so it will exit the method.
showSelected( true );
}
private function showSelected( useAnimation:Boolean = true ):void {
var tab:ToggleButton = toggleGroup.selectedItem as ToggleButton;
Starling.juggler.removeTweens(_bar);
if (!tab) {
// hide effect?
_bar.width = _bar.x = 0;
_bar.visible = false;
} else {
_bar.visible = true;
if (tab.numChildren == 0) {
trace("Tab buttons requires children.");
return;
}
// not the most performant approach, but works.
// Choose by default icon or label, whatever is available first.
var obj:DisplayObject = tab.getChildAt(tab.numChildren - 1);
obj.getBounds(tab.parent, rect);
if (animationFunction && useAnimation ) {
animationFunction();
} else {
_bar.x = rect.x;
_bar.width = rect.width;
}
}
}
//============================
// ANIMATION TYPES --
//============================
public function simpleAnimation():void {
Starling.juggler.tween(_bar, .25, {
x: rect.x, width: rect.width,
transition: Transitions.EASE_IN_OUT
});
}
public function specialAnimation():void {
// offset the initial X movement for the first half of the tween.
var initialMoveX:Number = 0;
var moveRight:Boolean = _bar.x < rect.x;
var halfDistance:Number = Math.abs(rect.x - _bar.x) / 2;
if (moveRight) {
Starling.juggler.tween(_bar, .3, {
x: _bar.x + initialMoveX, width: halfDistance, transition: Transitions.EASE_IN
});
Starling.juggler.tween(_bar, .4, {
delay: .3, x: rect.x, width: rect.width, transition: Transitions.EASE_OUT
});
} else {
Starling.juggler.tween(_bar, .3, {
x: rect.x + halfDistance,
width: halfDistance + _bar.width - initialMoveX,
transition: Transitions.EASE_IN
});
Starling.juggler.tween(_bar, .4, {
delay: .3, x: rect.x, width: rect.width, transition: Transitions.EASE_OUT
});
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment