Skip to content

ProcessIndicator for Starling

아이폰이 널리 사용되어지면서 함께 많이 사용하게 된 UI 중 하나가 ProcessIndicator 입니다. iOS 클래스 명으로는 UIActivityIndicatorView 가 바로 그것이죠.

이전에 사용하던 이 ProcessIndicator  를 Starling 용으로 만들어 보았습니다.  스탈링의 DisplayObject 와 기존 DisplayObject 는 거의 대동소이하므로 아무생각 없이 패키지만 스탈링으로 바꾸었습니다. 결과는…

잘 나오는데.. 어라 뭔가 이상하다~~~ 보통 이런 인디케이터의 경우 슬라이스의 각만큼 회전을 해야 합니다. 그런데 이 회전을 시키는 부분이 기존의 플래시와 스탈링이 약간 다릅니다. 기존의 rotation 은 360 즉 일반적인 각도로 회전하지만 스탈링의 rotation 은 라디안 값으로 회전합니다. 간단한거지만 아는데 반나절 걸렸음;;;; 그래서 원래 소스를 아래와 같이 변경 해야 합니다.

[as3]
rotation = rotation + (360 / slices) % 360; // degree 로 계산
rotation = deg2rad(( rad2deg(rotation) + (360 / slices)) % 360); // radian 으로 계산
[/as3]

어떤분들은 degree 와 radian 을 왔다갔다 할 필요가 있는지 궁굼해 하 실 수 있는데. 네, 없습니다. 처음부터 기준을 radian 으로 나눠 주면 저렇게 복잡하게 할 필요는 없습니다. 다만 spinnerSkin 을 플래시의 Shape 으로 만들기 때문에 이때는 degree 기준으로 슬라이스를 만들어야 합니다. 결국 조삼모사~ (제가 바꾸기 귀잖아서 그런거 절대 아님.)

전체 소스는 아래와 같습니다.

[as3]
package
{
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;

import starling.display.DisplayObjectContainer;
import starling.display.Image;
import starling.events.Event;
import starling.textures.Texture;
import starling.utils.deg2rad;
import starling.utils.rad2deg;

public class ProcessIndicator extends DisplayObjectContainer
{
private var _spinnerSkin:Image;

private var timer:Timer;
private var slices:int;
private var radius:int;
private var _image:Image;

public function ProcessIndicator(slices:int = 12, radius:int = 6)
{
super();
this.slices = slices;
this.radius = radius;

spinnerSkin = makeSpinner();

addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}

private function onAddedToStage(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
timer = new Timer(1000/30);
timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true);
timer.start();
}

private function onRemovedFromStage(event:Event):void
{
removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
timer.reset();
timer.removeEventListener(TimerEvent.TIMER, onTimer);
timer = null;
}

private function onTimer(event:TimerEvent):void
{
spinnerSkin.rotation = deg2rad(( rad2deg(spinnerSkin.rotation) + (360 / slices)) % 360);
}

private function makeSpinner():Image
{
var i:int = slices;
var degrees:int = 360 / slices;
var slider:flash.display.Sprite = new flash.display.Sprite;
while (i–)
{
var slice:Shape = getSlice();
slice.alpha = Math.max(0.2, 1 – (0.1 * i));
var radianAngle:Number = (degrees * i) * Math.PI / 180;
slice.rotation = -degrees * i;
slice.x = (Math.sin(radianAngle) * radius)+radius*2;
slice.y = (Math.cos(radianAngle) * radius)+radius*2;

slider.addChild(slice);
}

var bitamp:BitmapData = new BitmapData(slider.width, slider.height, true, 0);
bitamp.draw(slider);

var texture:Texture = Texture.fromBitmapData(bitamp, false, false);
var spinner:Image = new Image(texture);
spinner.pivotX = spinner.width >> 1;
spinner.pivotY = spinner.height >> 1;

return spinner;
}

private function getSlice():Shape
{
var slice:Shape = new Shape();
slice.graphics.beginFill(0x222222);
slice.graphics.drawRoundRect(-1, 0, 2, radius, radius*2, radius*2);
slice.graphics.endFill();

return slice;
}

//=====================================================================
//
// getter & setter
//
//=====================================================================

public function get spinnerSkin():Image
{
return _spinnerSkin;
}

public function set spinnerSkin(value:Image):void
{
if(_spinnerSkin == value)
{
return;
}

if(_spinnerSkin)
{
removeChild(_spinnerSkin);
}

_spinnerSkin = value;

if(this._spinnerSkin && this._spinnerSkin.parent != this)
{
_spinnerSkin.visible = true;
_spinnerSkin.touchable = false;
addChild(_spinnerSkin);
}
}

}
}
[/as3]

결과물

원래 이번 포스팅의 목적은 radian 과  degree 의 집중분석이었으나 연속 포스팅으로 텐션이 떨어져서 소스 공유 정도로 마무리 하겠습니다.

샘플 소스

[button url=”https://sewonist.com/wp-content/uploads/2013/03/ProcessIndicator.zip”]Download ProcessIndicator.zip[/button]

Leave a Reply

Your email address will not be published. Required fields are marked *