Home > 梅原 > TweenButton

TweenButton

20100330
Category:梅原 /Tags:

Progression4での話。
最近、微妙に振る舞いの違うボタンをいくつか作る必要があった。
トグルボタン、ラジオボタン、それらをハイブリッドみたいなボタン。
なるべく共通化してたんだけど、やっぱり作り進むうちに、違いが出て来てしまって、差し替え時にミスをしがちになった。
汎用的なボタンを作るか、インターフェイスを用いるべきだったんだと思った。
とりあえず、普通、トグル、ラジオに対応するボタンを作ってみた。

▼Wonderfl

▼Wonderfl
http://wonderfl.net/code/1f13993add15deb3ecf8c65398c0ace623345a6c

▼ActionScript AS3(FP9)

/*
 * Progression4での話。
 *
 * 最近、微妙に振る舞いの違うボタンをいくつか作る必要があった。
 * トグルボタン、ラジオボタン、それらをハイブリッドみたいなボタン。
 * なるべく共通化してたんだけど、やっぱり作り進むうちに、
 * 違いが出て来てしまって、差し替え時にミスをしがちになった。
 *
 * 汎用的なボタンを作るか、インターフェイスを用いるべきだったんだと思った。
 *
 * とりあえず、普通、トグル、ラジオに対応するボタンを作ってみた。
*/

// forked from nium's Progression 4 BasicAppConfig
package {
	import flash.display.*;
	import jp.progression.config.*;
	import jp.progression.debug.*;
	import jp.progression.*;

	public class Main extends Sprite {

		public var manager:Progression;

		public function Main() {
			Progression.initialize( new BasicAppConfig() );
			manager = new Progression( "index", stage, IndexScene );

			//Debugger.addTarget( manager );

			manager.goto( manager.root.sceneId );
		}
	}
}

import flash.display.*;
import flash.net.URLRequest;

import jp.progression.casts.*;
import jp.progression.commands.*;
import jp.progression.commands.display.*;
import jp.progression.commands.lists.*;
import jp.progression.commands.net.*;
import jp.progression.commands.tweens.*;
import jp.progression.data.*;
import jp.progression.events.*;
import jp.progression.scenes.*;

class IndexScene extends SceneObject {

	public function IndexScene() {
		//デフォルト
		new TweenButton( { id:"tweenButton0", x:50, y:50 } );

		//デフォルト+文字+ダウンイメージを使わない
		new TweenButton( { id:"tweenButton1", x:50, y:100 },{text:"Button",isUseDownImage:false} );

		//トグル+tweenの時間設定+文字のせ
		new TweenButton( { id:"tweenButton2", x:50, y:200 }, { isToggle:true, time:0.3, text:"トグル" } );

		//on/offで違う文字のせ+初期状態でon
		new TweenButton( { id:"tweenButton3", x:50, y:250 }, { isToggle:true, onText:"ON", offText:"OFF", isOn:true } );

		//ラジオボタンの設定+tween無+selected
		var group:Array = ["radio0", "radio1", "radio2"];
		new TweenButton( { id:"radio0", x:50, y:350 }, { text:"Radio0", radioGroup:group, time:0 , selected:true } );
		new TweenButton( { id:"radio1", x:150, y:350 }, { text:"Radio1", radioGroup:group, time:0 } );
		new TweenButton( { id:"radio2", x:250, y:350 }, { text:"Radio2", radioGroup:group, time:0 } );

		//画像のボタン
		var offUpImg:CastImageLoader = new CastImageLoader();
		offUpImg.load(new URLRequest("http://farm3.static.flickr.com/2499/3828917483_8948414d57_o.jpg"));
		var offOverImg:CastImageLoader = new CastImageLoader();
		offOverImg.load(new URLRequest("http://farm3.static.flickr.com/2664/3828917495_8e21ea52c1_o.jpg"));
		var offDownImg:CastImageLoader = new CastImageLoader();
		offDownImg.load(new URLRequest("http://farm4.static.flickr.com/3542/3829716284_3f77a81e73_o.jpg"));

		new TweenButton( { id:"tweenButton4", x:200, y:50 }, { offUp:offUpImg, offOver:offOverImg,offDown:offDownImg } );

	}

	protected override function atSceneLoad():void {
		addCommand(
			new AddChild(container, "tweenButton0"),
			new AddChild(container, "tweenButton1"),
			new AddChild(container, "tweenButton2"),
			new AddChild(container, "tweenButton3"),
			new AddChild(container, "radio0"),
			new AddChild(container, "radio1"),
			new AddChild(container, "radio2"),
			new AddChild(container, "tweenButton4"),
			"Progression 4"
		);
	}

	protected override function atSceneInit():void {
		addCommand(
			"BasicAppConfig Test"
		);
	}

	protected override function atSceneGoto():void {
		addCommand(
		);
	}
}

import flash.display.Shape;
import flash.geom.Matrix;
import flash.text.TextField;
import flash.display.Bitmap;

class TweenButton extends CastButton {
	private var _offUp:DisplayObject;
	private var _offOver:DisplayObject;
	private var _offDown:DisplayObject;
	private var _onUp:DisplayObject;
	private var _onOver:DisplayObject;
	private var _onDown:DisplayObject;

	private var _up:CastSprite;
	private var _over:CastSprite;
	private var _down:CastSprite;

	private var _isOn:Boolean;
	private var _selected:Boolean;
	private var _isImageSwap:Boolean;
	//Downボタンを用意しない場合も多いので、
	//無くてもダミーが表示しないようにするには
	//isUseDownImage = false;にする。
	private var _isUseDownImage:Boolean = true;
	//tweenの時間。0にするとtweenerの呼び出しもない
	private var _time:Number = 0.6;
	private var _isToggle:Boolean;
	private var _text:String;
	private var _onText:String;
	private var _offText:String;
	private var _radioGroup:Array;

	private var _initialized:Boolean;

	public function TweenButton( initObject:Object = null , extendsObject:Object = null) {

		super(initObject);

		if (extendsObject) {
			for (var str:String in extendsObject) {
				this["_" + str] = extendsObject[str];
			}
		}

		if (!_onText) {
			_onText = _text?_text:null;
		}
		if (!_offText) {
			_offText = _text?_text:null;
		}

		if (_isToggle) {
			if (!_onUp) {
				_onUp = getImage(0xFFFF00, _onText);
			}
			if (!_onOver){
				_onOver = getImage(0x00FFFF, _onText);
			}
			if (!_onDown && _isUseDownImage){
				_onDown = getImage(0xFF00FF, _onText, 1);
			}
		}

		if (!_offUp) {
			_offUp = getImage(0xFF0000, _offText);
		}
		if (!_offOver) {
			_offOver = getImage(0x00FF00, _offText);
		}
		if (!_offDown && _isUseDownImage) {
			_offDown = getImage(0x0000FF, _offText, 1);
		}

		_isImageSwap = true;
		this.buttonMode = true;

		_up = new CastSprite();
		_over = new CastSprite();

		if(_offDown && _onDown){
			_down = new CastSprite();
		}else if (_offDown) {
			if (!_isToggle) {
				_down = new CastSprite();
			}
		}

		_up.addChild(_offUp);
		_over.addChild(_offOver);

		if (_up) {
			this.addChild(_up);
			_up.visible = true;
		}
		if (_over) {
			this.addChild(_over);
			_over.visible = false;
		}
		if (_down) {
			_down.addChild(_offDown);
			this.addChild(_down);
			_down.visible = false;
		}

		//初騎状態を設定
		this.isOn = _isOn;
		this.selected = _selected;
		_initialized = true;
	}
	private function getImage(rgb:int = 0xFF0000, text:String = null, ty:Number = 0):Bitmap {
		var shape:Shape = new Shape();
		shape.graphics.beginFill(rgb,0.5);
		shape.graphics.drawRoundRect(0,0,60,20,8,8);
		shape.graphics.endFill();
		shape.graphics.beginFill(rgb,0.5);
		shape.graphics.drawRoundRect(2,2,56,16,6,6);
		shape.graphics.endFill();
		var bitmapData:BitmapData = new BitmapData(shape.width, shape.height);
		bitmapData.draw(shape);
		if(text){
			var textField:TextField = new TextField();
			textField.text = text;
			textField.width = shape.width;
			textField.autoSize = "center";
			bitmapData.draw(textField, new Matrix(1, 0, 0, 1, 0, ty));
		}
		return new Bitmap(bitmapData);
	}

	//選択状態を維持する用
	public function get selected():Boolean { return _selected };
	public function set selected(value:Boolean):void {
		if (_initialized && _selected == value) { return };
		_selected = value;
		if (_over || _down) {
			if(_over){
				_over.visible = value;
			}
			if(_down){
				_down.visible = value;
			}
			_isImageSwap = !value;
		}
		this.mouseEventEnabled = !value;
		this.mouseEnabled = !value;
	}

	//ボタンとして機能するんだけど、イメージの差し替えはしない時用
	public function get isImageSwap():Boolean { return _isImageSwap };
	public function set isImageSwap(value:Boolean):void {
		if (_isImageSwap == value) { return };
		_isImageSwap = value;
	}

	//トグルが効いているときに画像の差し替えをする
	//onを表示しているときには、trueを返す。
	public function get isOn():Boolean { return _isOn };
	public function set isOn(value:Boolean):void {
		if (_initialized && _isOn == value) { return };
		_isOn = value;
		if (!_isToggle) { return };
		_up.removeAllChildren();
		_over.removeAllChildren();
		if(_down){
			_down.removeAllChildren();
		}
		if (value) {
			_up.addChild(_onUp);
			_over.addChild(_onOver);
			if(_down){
				_down.addChild(_onDown);
			}
		}else {
			_up.addChild(_offUp);
			_over.addChild(_offOver);
			if(_down){
				_down.addChild(_offDown);
			}
		}
	}

	//トグルを使う場合はtrueにする。
	public function get isToggle():Boolean { return _isToggle };
	public function set isToggle(value:Boolean):void {
		if (_isToggle == value) { return };
		_isToggle = value;
	}

	override protected function atCastMouseUp():void {
		if (_isImageSwap) {
			isOn = !isOn;
			if (_down) {
				_down.visible = false;

				//downが無いときに連続のクリックの時にわかりやすくするには、
				//_overを消すといいかも。
			//}else {
				//if (_over) {
					//_over.visible = false;
				//}
			}
		}
		//ラジオボタン用のグループがある場合に、自分以外を非selected表示に
		if (_radioGroup) {
			var n:int = _radioGroup.length;
			for (var i:int = 0; i < n; i++) {
				if ((getInstanceById(_radioGroup[i]) as TweenButton) != this) {
					(getInstanceById(_radioGroup[i]) as TweenButton).selected = false;
				}
			}
			this.selected = true;
		}
	}

	override protected function atCastMouseDown():void {
		if (_isImageSwap) {
			if (_down) {
				_down.visible = true;
			}else {
				//連続のクリックの時にはわかりにくいので、表示
				if (_over) {
					_over.visible = true;
				}
			}
		}
	}

	override protected function atCastRollOver():void {
		if (_isImageSwap) {
			if (_over) {
				if (_time > 0) {
					var sList:SerialList = new SerialList();
					sList.addCommand(
						function():void {
							_over.visible = true;
							_over.alpha = 0;
						},
						new DoTweener(_over,{alpha:1, time:_time, transition:"easeOutQuart"})
					);
					sList.execute();
				}else {
					_over.alpha = 1;
					_over.visible = true;
				}
			}
		}
	}

	override protected function atCastRollOut():void {
		if (_isImageSwap) {
			if (_over) {
				if (_time > 0) {
					var sList:SerialList = new SerialList();
					sList.addCommand(
						new DoTweener(_over,{alpha:0, time:_time, transition:"easeOutQuart"}),
						function():void {
							_over.visible = false;
						}
					);
					sList.execute();
				}else {
					_over.visible = false;
				}
			}
		}
	}
}

関連記事:

Comments are closed.