Спиннер. Кому лень писать.
Выкладываю спиннер - www.flashstudio.com.ua/spinner
Писался для тачскрин(колесо мышки не юзается).
Несложно кустомизируется, использует aze в качестве твиннера.
package { import aze.motion.eaze; import flash.display.Sprite; import flash.display.Stage; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Rectangle; public class Spinner extends mcSpinner { private const HEIGHT_OF_NUMBER:uint = 114; private const HEIGHT_OF_SPINNER:uint = 570; private const MAX_VALUE:uint = 10; private const MIDDLE_VALUE:uint = 2; private var _isMove:Boolean; private var _lastMouseY:Number; private var _numbersLine:Sprite; private var _currentNumber:int; private var _lastEnterFrameMouseY:Number; private var _mouseAcceleration:int; private var _deltaEazeMove:Number; public function Spinner() { super(); this.tfLabel.text = MIDDLE_VALUE.toString(); this.tfLabel.mouseEnabled = false; this.mouseChildren = false; addEventListener(Event.ADDED_TO_STAGE, init); } public function init(event:Event):void { _currentNumber = MIDDLE_VALUE; removeEventListener(Event.ADDED_TO_STAGE, init); //линк на сцену нужен для уничтожения лиссенеров в том случае если спиннер уже убрали из дисплейлиста //здесь будут наши числа _numbersLine = new Sprite(); //генерируем намберсы, на один больше чем помещается в спиннере, собственно им мы и будем играть //mcNumber это подготовленный мувик в либе for (var i:uint = 0; i < (HEIGHT_OF_SPINNER/HEIGHT_OF_NUMBER + 1); i++) { var number:mcNumber = new mcNumber(); //присваиваем число тексту текстового поля в мувике number.tfLabel.text = i.toString(); _numbersLine.addChild(number); number.y = i * HEIGHT_OF_NUMBER; } //добавляем все эти this.mcNumbers.addChild(_numbersLine); //слушаем нажатие и движение по спиннеру this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); this.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); } //возвращаем текущее значение нашего спиннера //не придумал как отсчитывать при движении количество целых сдвигов, поэтому беру чисто из текстового поля //далее будет понятно почему так public function getCurrentNumber():uint { //берем первый намберс в дисплейлисте(это всегда верхний намберс, он может быть как в состоянии -1(спрятан сверху под маской) так и в состоянии 0) var firstNumber:mcNumber = _numbersLine.getChildAt(0) as mcNumber; var currentNumber:mcNumber; if(firstNumber.y < -5) { //поэтому берем либо "средний" элемент и на один выше currentNumber = _numbersLine.getChildAt( MIDDLE_VALUE + 1) as mcNumber; }else { //либо просто средний элемент currentNumber = _numbersLine.getChildAt(MIDDLE_VALUE) as mcNumber; } return int(currentNumber.tfLabel.text) } // INNERTION // доводим намберсы до ровных позиций после того как пользователь прокрутил спиннер без иннерции, тоесть медленно и спокойно // берем верхний намберс и смотрим выше он середины или нет // и доводим на разницу нуля и высоты этого намбера private function leadLines():void { var firstNumber:mcNumber = _numbersLine.getChildAt(0) as mcNumber; var currentY:Number = Math.abs(firstNumber.y); var i:uint; var number:mcNumber; if( currentY >= HEIGHT_OF_NUMBER/2 ) { for (i = 0; i < _numbersLine.numChildren; i++) { number = _numbersLine.getChildAt(i) as mcNumber; eaze(number).to(.3, { y:number.y - HEIGHT_OF_NUMBER + currentY}); } eaze(this).delay(.3).onUpdate(checkNumbersPositions); eaze(this.mcLines.mcLine1).to(.3, { y:this.mcLines.mcLine1.y - HEIGHT_OF_NUMBER + currentY}).onUpdate(moveSecondBGLine).onComplete(showLabel); }else { for (i = 0; i < _numbersLine.numChildren; i++) { number = _numbersLine.getChildAt(i) as mcNumber; eaze(number).to(.3, { y:number.y + currentY}); } //во время доводки играем "внешним" намбером eaze(this).delay(.3).onUpdate(checkNumbersPositions); //в конце довдки, отображаем текущий номер на верхней индикационной плашечке eaze(this.mcLines.mcLine1).to(.3, { y:this.mcLines.mcLine1.y + currentY}).onUpdate(moveSecondBGLine).onComplete(showLabel); } } //тонкая доводка после иннерционного вращения, когда юзер "запустил" спиннер //практически тоже самое что leadLines, но без твиннера так как довдки очень маленькие(пару пикселей) private function leadLinesAfetrInnertial():void { var firstNumber:mcNumber = _numbersLine.getChildAt(0) as mcNumber; var currentY:Number = Math.abs(firstNumber.y); var i:uint; var number:mcNumber; if(currentY >= HEIGHT_OF_NUMBER/2) { for (i = 0; i < _numbersLine.numChildren; i++) { number = _numbersLine.getChildAt(i) as mcNumber; number.y = number.y - HEIGHT_OF_NUMBER + currentY; } checkNumbersPositions(); this.mcLines.mcLine1.y = this.mcLines.mcLine1.y - HEIGHT_OF_NUMBER + currentY; moveSecondBGLine(); }else { for (i = 0; i < _numbersLine.numChildren; i++) { number = _numbersLine.getChildAt(i) as mcNumber; number.y = number.y - currentY; } checkNumbersPositions(); this.mcLines.mcLine1.y = this.mcLines.mcLine1.y - currentY; moveSecondBGLine(); } showLabel(); } //показываем текущее значение спиннера private function showLabel():void { eaze(this.tfLabel).to(.2,{alpha:1}); eaze(this.mcLabelHolder).to(.2,{alpha:1}); this.tfLabel.text = getCurrentNumber().toString(); } // NUMBERS //двигаем намберсы на дельту private function moveNumbers(delta:Number):void { //для каждого намбера задаем твиннер for (var i:int = 0; i < _numbersLine.numChildren; i++) { var number:mcNumber = _numbersLine.getChildAt(i) as mcNumber; number.y -= delta; } //проверяем когда пора перемещать транзитный намбер checkNumbersPositions(); } //вот тут сама магия и происходит, _currentNumber отвечает на сколько намберосов произошло смещение. //но его нельзя использовать для getCurrentNumber, так как движение может быть не защитанно(если довдка спустила намберы вниз) private function checkNumbersPositions():void { var number:int; var lastNumber:mcNumber = _numbersLine.getChildAt(_numbersLine.numChildren - 1) as mcNumber; if(lastNumber.y > HEIGHT_OF_SPINNER) { _currentNumber --; if(_currentNumber == -1) _currentNumber = MAX_VALUE; lastNumber.y = _numbersLine.getChildAt(0).y - HEIGHT_OF_NUMBER; _numbersLine.addChildAt(lastNumber, 0); number = _currentNumber - 2; if(number < 0) { number = MAX_VALUE + number + 1; } lastNumber.tfLabel.text = number.toString(); } var firstNumber:mcNumber = _numbersLine.getChildAt(0) as mcNumber; if(firstNumber.y < -firstNumber.height) { _currentNumber ++; if(_currentNumber == (MAX_VALUE + 1)) _currentNumber = 0; firstNumber.y = _numbersLine.getChildAt(_numbersLine.numChildren - 1).y + HEIGHT_OF_NUMBER; _numbersLine.addChildAt(firstNumber, _numbersLine.numChildren - 1); number = _currentNumber + 3; if(number > MAX_VALUE) { number = number - MAX_VALUE - 1; } firstNumber.tfLabel.text = number.toString(); } } // BG LINES //в проекте исопльзуется две полоски беграунда которые следуют друг за другом //двигаем первую private function moveBGLines(mouseDelta:Number):void { this.mcLines.mcLine1.y -= mouseDelta; moveSecondBGLine(); } //и подстраиваем вторую private function moveSecondBGLine():void { if(this.mcLines.mcLine1.y < 0) { this.mcLines.mcLine2.y = this.mcLines.mcLine1.y + HEIGHT_OF_SPINNER; } if(this.mcLines.mcLine1.y > 0) { this.mcLines.mcLine2.y = this.mcLines.mcLine1.y - HEIGHT_OF_SPINNER; } checkBGLinesPositions(); } //и при необходимости переносим первую полоску вверх или вниз если вторая уже закончилась private function checkBGLinesPositions():void { if(this.mcLines.mcLine1.y < - HEIGHT_OF_SPINNER) { this.mcLines.mcLine1.y = this.mcLines.mcLine2.y + HEIGHT_OF_SPINNER; } if(this.mcLines.mcLine1.y > HEIGHT_OF_SPINNER) { this.mcLines.mcLine1.y = this.mcLines.mcLine2.y - HEIGHT_OF_SPINNER; } } // MOUSE HENDLERS //собственно наше движение //при началае движения прячем плашку с текущим значением спиннера //и смещаем на дельту наши намберсы и полоски бекграунда //для поиска дельты используем _lastMouseY и сравниваем с текущим положением мыкурсораи protected function onMouseMove(event:MouseEvent):void { if(!_isMove) return; if(this.tfLabel.alpha == 1)eaze(this.tfLabel).to(.2,{alpha:0}); if(this.mcLabelHolder.alpha == 1)eaze(this.mcLabelHolder).to(.2,{alpha:.9}); var mouseDelta:Number = _lastMouseY - mouseY; moveBGLines(mouseDelta); moveNumbers(mouseDelta); _lastMouseY = mouseY; } //юзер отпустил мышь. Проверяем если движение было плавным просто довдим до ближайшего значения(leadLines) если же это был резкий жест - запускаем иннерцию //проверка резкости движения происходит по энтерфрейму, каждый энтерфрейм проверяем дистанцию между прошлым и текущим положением курсора используюя(_lastEnterFrameMouseY) //также ставим "порог резкости" в 5, можно поменять protected function onMouseUp(event:MouseEvent):void { _isMove = false; this.removeEventListener(Event.ENTER_FRAME, onEnterFrame); this.removeEventListener(MouseEvent.MOUSE_OUT, onMouseUp); stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); if(_mouseAcceleration > 5 || _mouseAcceleration < -5) { //ограничение резкости if(_mouseAcceleration > 90) _mouseAcceleration = 90; if(_mouseAcceleration < -90) _mouseAcceleration = -90; _deltaEazeMove = 0; //15 тоже подобрано экспериментально var innertion:int = _mouseAcceleration/15; //находим новое положение var newPosition:int = innertion*HEIGHT_OF_NUMBER; var firstNumber:mcNumber = _numbersLine.getChildAt(0) as mcNumber; //с доводкой newPosition = newPosition + firstNumber.y; //и запускаем твиннер который дерагет сеттер move eaze(this).to((.4 + Math.abs(_mouseAcceleration/100)), { move:newPosition}).onComplete(leadLinesAfetrInnertial); }else { leadLines(); } } //здесь мы грубо говоря симулируем вращение спиннер мышкой public function set move(value:Number):void { moveBGLines(value - _deltaEazeMove); moveNumbers(value - _deltaEazeMove); _deltaEazeMove = value; } //геттер нужен для aze я возвращаю 0 это ничего не меняет public function get move():Number { return 0; } //очищаем все твины при клике и начинаем "прямое" прокручивание спиннера в след за курсором //также слушаем маус ап и маус аут(обрабатываем его также как и маус ап) protected function onMouseDown(event:MouseEvent):void { _isMove = true; for (var i:int = 0; i < _numbersLine.numChildren; i++) { var number:mcNumber = _numbersLine.getChildAt(i) as mcNumber; eaze(number).killTweens(); } eaze(this).killTweens(); eaze(this.mcLines.mcLine1).killTweens(); _lastMouseY = mouseY; addEventListener(Event.ENTER_FRAME, onEnterFrame); this.addEventListener(MouseEvent.MOUSE_OUT, onMouseUp); stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); } //считаем ускорение движение курсора protected function onEnterFrame(event:Event):void { _mouseAcceleration = _lastEnterFrameMouseY - mouseY; _lastEnterFrameMouseY = mouseY; } } }
пофикшено
Всего комментариев 34
Комментарии
12.06.2013 11:12 | |
Наблюдаются глюки. Пару раз прокрутил, туда-сюда. И в итоге на шкале:85,80,82 и все...
|
12.06.2013 14:18 | |
Я глюков не заметил, но и писать там самому 5 минут
|
12.06.2013 16:08 | |
Если много кликать, то все таки глюки есть.
|
13.06.2013 15:26 | |
Отправка через мыло нужна была как раз для того чтобы узнать скольким оно пригодилось(уже есть один человек). В инете я не нашел ни одного примера/туториала/исходника с хоть както пхожим компонентом. Также с непостояннотью заказчиков по этому проекту я изначально делал возможность действительно легко кустомизировать.
А в целом, да, это не особо развивающий/полезный пост, я согласен. И все же, думаю, комунить пригодится. Если бы я нашел подобную статью, взял бы не задумываясь, так как времени на написания не было практически. (думаю этот компонент может быть полезен для мобильных апп) |
|
Обновил(-а) 3p.station 13.06.2013 в 17:05
|
13.06.2013 17:07 | |
Зачем же удалять мои верные сообщения, неприятно когда говорят правду да? Особенно интересно почему же удален кусок про КОД, который действительно написан ужасно!
|
13.06.2013 17:08 | |
_stage = stage; это кстати тоже жесть)
|
13.06.2013 17:13 | |
чувак уймися а
почему линк на стейдж это жесть? |
13.06.2013 19:36 | |
я то думал что если ДО не в дисплейлисте, то стейджа нету у него...
|
13.06.2013 19:38 | |
А что с интерфреймом?
|
13.06.2013 23:11 | |
Цитата:
GBee глюк какойто вроде есть
|
19.06.2013 11:23 | |
Цитата:
Пример атас.
|
19.06.2013 12:24 | |
20.06.2013 00:27 | |
Цитата:
После удаления из Дисплей листа мы не сможем отписаться, т.к. stage==null
|
20.06.2013 01:13 | |
Цитата:
Плохой пример, для этого есть Event.REMOVED_FROM_STAGE
|
20.06.2013 11:49 | |
Цитата:
А вы уверены, что стейдж будет все еще доступен?
|
20.06.2013 12:45 | |
Ок, я просто уточнил. Просто REMOVED это как бы совершенное дело - удален. Поэтому интересно.
|
20.06.2013 13:26 | |
Цитата:
событие рассылается перед тем как displayobject будет удален из списка отображение
|
20.06.2013 15:03 | |
Цитата:
Просто REMOVED это как бы совершенное дело - удален. Поэтому интересно.
|
20.06.2013 19:18 | |
вообщем ща вроде работает ок.
|
21.06.2013 15:05 | |
3p.station, вам ссылка: http://voobschem.ru/ (потом комментарий мой удалите)
|
23.06.2013 09:52 | |
благодарю!
|
Последние записи от 3p.station
- Спиннер. Кому лень писать. (12.06.2013)
- AIR. Показываем видео HD на несколько экранов (24.04.2013)
- Парсинг линков в стринге. (03.08.2011)
- автоотправка событий (24.05.2011)
- Список актуальных камер юзера. (11.03.2011)