Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 26.07.2011, 08:27
BornTOFree вне форума Посмотреть профиль Отправить личное сообщение для BornTOFree Найти все сообщения от BornTOFree
  № 1  
Ответить с цитированием
BornTOFree

Регистрация: Oct 2010
Сообщений: 85
По умолчанию Свой Scrollbar (проблема с прокруткой содержимого)

Есть необходимость на экшн скрипте написать свой скроллбар, подобие флешевого компонента Scrollbar(без стрелок, только слайдер)

Проблема в следующем:
Слайдер меняет свою высоту в зависимости от высоты содержимого. Если размеры содержимого превышают минимальные размеры слайдера, то высоту слайдера устанавливаю постоянной, чтобы ползунок не уходил в минус по высоте. И вот здесь начинаются проблемы. Если раньше в расчет входила высота слайдера, то с фиксированной высотой содержимое прокручивается не до конца. Пока не знаю, как это исправить.

Вот исходный код. Scrollbar.zip
Там два варианта слайдера.
Первый скроллит содержимое в 100 строк и все нормально, т.к. содержимое не превышает высоту слайдера. Второй скроллер прокручивает содержимое в 300 строк и здесь проблема, т.к. содержимое превышает высоту слайдера.

Возможно мое решение в корне не верно, любые советы по теме приветствуются


Последний раз редактировалось BornTOFree; 26.07.2011 в 08:30.
Старый 26.07.2011, 09:05
goodguy вне форума Посмотреть профиль Найти все сообщения от goodguy
  № 2  
Ответить с цитированием
goodguy
Banned
[+1 05.11.11]
[+1 09.08.11]

Регистрация: Jan 2010
Адрес: РФ. Кемеровская область
Сообщений: 3,243
Цитата:
Первый скроллит содержимое в 100 строк и все нормально, т.к. содержимое не превышает высоту слайдера. Второй скроллер прокручивает содержимое в 300 строк и здесь проблема, т.к. содержимое превышает высоту слайдера.
Надо расчитывать процентное соотношение, а не сопоставлять высоту скроллера и прокручиваемого объекта напрямую.
У меня в скроллере высота прокрутки расчитывалась так:
Код AS3:
public function update():void {
try {
	_scrollPercent = Math.floor((_container.y / _scrollHeight) * 100); // расчитываем процент смещения ползунка, относительно всей высоты скроллбара
	_shopCorelation = _objectToScroll.height - _height; // разница высоты прокручиваемого дисплей объекта, и высоты скроллбара
	_objectToScroll.y = int(_objectToScrollInitialY - (_shopCorelation / 100) * _scrollPercent); // то, на сколько нужно переместить объект при движении ползунка
	_shopScrollPercent = Math.floor((y - _objectToScroll.y) / _shopCorelation * 100); // процент смещения прокручиваемого объекта
	if (_shopScrollPercent != previousScrollPercent) {
	previousScrollPercent = _shopScrollPercent;
	}
} catch (e:Error) {}
}
_container - это сам ползунок, который тягается мышкой
_shopCorelation - это соотношение высоты скроллбара и высоты прокручиваемого дисплей объекта
_scrollHeight - это общая высота скроллбара, минус высота ползунка

Метод вызывается по энтер фрейму.


Последний раз редактировалось goodguy; 26.07.2011 в 09:10.
Старый 26.07.2011, 09:54
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 3  
Ответить с цитированием
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
А зачем Вам это хардкодерство?
1. Зачем эти магические числа – 20, 100, 1000, 10000? Операции со строками вообще не понял, если честно..
2. Зачем InteractiveObject? Разве свойств DisplayObject'a недостаточно для скроллера?
3. Зачем принимать ссылку на stage? Разве Вы собираетесь скроллировать объект, не добавленный на стейдж, скроллбаром, не добавленным на стейдж? Есть событие ADDED_TO_STAGE, воспользуйтесь им для инициализации слушателей.
4.
Код AS3:
if(Math.ceil(container.height-(container.height - maskCont.height)-offset) < 20) { 
//Если высота содержимого превышает высоту ползунка, то задается постоянная высота 
sliderH = 20;
Здесь вообще никак не учитывается высота содержимого – раскройте скобки, получится "maskCont.height - offset". И снова не понял логики.. Что Вы называете "высотой ползунка"? Ползунок это кнопка, которую таскаем (pimp).. Это ее высота должна подстраиваться под контент, причем именно если высота контента превышает высоту трека. А если не превышает, то скроллбар вообще не должен показываться. Ну и наконец условие у Вас - "если А меньше В", а не "если А превышает В".
5. Насколько я понял Вашу логику, Вы пытаетесь сделать движок скроллбара такой высоты, чтобы оставшаяся часть трека – путь, который может пройти движок – равнялась разнице между высотой контента и его маски, помноженной на коэфициент.
а. Вычисляем "путь контента" - разницу высоты контента и его маски.
b. Вычитаем полученное из высоты трека. Сравниваем остаток с минимальным значением для высоты движка (20). Если остаток меньше (< 20), вычисляем коэфициент – "путь движка" / "путь контента" а сам движок оставляем минимального размера, если больше - оставляем коэфициент равным единице и делаем движок такой высоты, чтобы "путь движка" равнялся "пути контента", то есть "высота движка" = "высота трека" - "путь контента". И в результирующей формуле просто умножаем (делим?) "-у" движка на коэфициент, но не 10, а динамически рассчитанный выше, учитывающий все размеры.
6. И да, для 100 строк у Вас тоже неправильно показывается. Я вижу только верхушку сотой.

Добавлено через 13 минут
Для размышлений.. AS2 и движок постоянного размера. Но может почерпнете чтонибудь.
http://flasher.ru/forum/showthread.php?t=111891
http://www.flasher.ru/forum/showpost...48&postcount=6

Добавлено через 11 часов 51 минуту
Код AS3:
package controls {
 
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.display.Stage;
 
	public class ScrollBox extends Sprite {
 
		private var _mask		:Sprite;
		private var _container	:Sprite;
		private var _pimp		:Sprite;
		private var _track		:Sprite;
		private var _height		:Number;
		private var _k			:Number;
		private var _noScroll	:Boolean;
		private var _grabY		:Number;
		private var _pimpMinHeight		:Number;
		private var _scrollerWidth		:Number;
		private var _scrollerPimpColor	:uint;
 
		public function ScrollBox(content:DisplayObject, boxHeight:Number, scrollerWidth:Number = 10, scrollerPimpColor:uint = 0x808080) 
		{
			_scrollerPimpColor = scrollerPimpColor;
			_scrollerWidth = scrollerWidth;
			_height = boxHeight;
			_container = createSprite(content.width, content.height, 0x00FFFFFF);
			_container.addChild(content);
			_mask = createSprite(content.width, _height, 0xFF0000);
			_container.mask = _mask;
			this.addChild(_container);
			this.addChild(_mask);
			_noScroll = content.height <= _height;
			if (this.stage != null) 
			{
				init();
			}
			else
			{
				this.addEventListener(Event.ADDED_TO_STAGE, init);
			}
		}
 
		private function init(event:Event = null):void
		{
			if (_noScroll) 
			{
				return;
			}
			this.addEventListener(MouseEvent.MOUSE_WHEEL, wheelHandler);
			_pimpMinHeight = _scrollerWidth * 2;
			var contentWay:Number = _container.height - _height;
			var pimpHeight:Number = _height - contentWay;
			var maxPimpWay:Number = _height - _pimpMinHeight;
			if (contentWay > maxPimpWay)
			{
				_pimp = createSprite(_scrollerWidth, _pimpMinHeight, _scrollerPimpColor);
				_k = contentWay / maxPimpWay;
			}
			else
			{
				_pimp = createSprite(_scrollerWidth, pimpHeight, _scrollerPimpColor);
				_k = 1;
			}
			_track = createSprite(_scrollerWidth, _height, 0x00FFFFFF);
			_track.x = _container.x + _container.width + 2;
			_pimp.x = _track.x;
			addChild(_track);
			addChild(_pimp);
			_pimp.addEventListener(MouseEvent.MOUSE_DOWN, pimpDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, pimpUpHandler);
		}
 
		private function createSprite(initWidth:Number, initHeight:Number, color:uint = 0xCCCCCC):Sprite
		{
			var g:Sprite = new Sprite();
			g.graphics.beginFill(color);
			g.graphics.drawRect(0, 0, initWidth, initHeight);
			g.graphics.endFill();
			return g;
		}
 
		private function wheelHandler(event:MouseEvent):void 
		{
			_pimp.y = Math.min(Math.max(0, _pimp.y - event.delta), _height - _pimp.height)
			moveContent();
		}
 
		private function movePimp(event:MouseEvent):void 
		{
			_pimp.y = Math.min(Math.max(0, this.mouseY - _grabY), _height - _pimp.height)
			moveContent();
		}
 
		private function moveContent():void 
		{
			_container.y = -_pimp.y * _k;
		}
		private function pimpDownHandler(event:MouseEvent):void 
		{
			_grabY = _pimp.mouseY;
			stage.addEventListener(MouseEvent.MOUSE_MOVE, movePimp);
		}
		private function pimpUpHandler(event:MouseEvent):void 
		{
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, movePimp);
		}
	}
}
Код AS3:
package {
	import components.Content;
 
	import controls.ScrollBox;
 
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
 
	public class Test_as extends Sprite {
 
		public function Test_as(){
			this.stage.scaleMode = StageScaleMode.NO_SCALE;
			this.stage.align = StageAlign.TOP_LEFT;
 
			var content:Content = new Content(25);
			var scroller:ScrollBox = new ScrollBox(content, stage.stageHeight - 20);
			addChild(scroller);
			scroller.x = 50;
			scroller.y = 10;
 
			var content1:Content = new Content(30);
			var scroller1:ScrollBox = new ScrollBox(content1, stage.stageHeight - 20, 5, 0x408090);
			addChild(scroller1);
			scroller1.x = 250;
			scroller1.y = 10;
 
			var content2:Content = new Content(300);	
			var scroller2:ScrollBox = new ScrollBox(content2, stage.stageHeight - 20);
			addChild(scroller2);
			scroller2.x = 450;
			scroller2.y = 10;
		}
 
	}
}
__________________
Reality.getBounds(this);


Последний раз редактировалось Wolsh; 26.07.2011 в 21:44.
Старый 27.07.2011, 16:48
BornTOFree вне форума Посмотреть профиль Отправить личное сообщение для BornTOFree Найти все сообщения от BornTOFree
  № 4  
Ответить с цитированием
BornTOFree

Регистрация: Oct 2010
Сообщений: 85
goodguy, спасибо
Цитата:
Метод вызывается по энтер фрейму.
У меня недавно был не самый приятный опыт с этим ENTER_FRAME и я теперь пытаюсь обходить его стороной, без острой необходимости в нем.

Wolsh, большое спасибо. Ваши ответы на вес золота.
Цитата:
А зачем Вам это хардкодерство?
Мне нечего ответить, вы сами все сказали, весь класс один сплошной хардкод. Пытался быстро разобраться с этим скроллом, решить основные требования, потом вернуться подправить и оптимизировать код, в итоге завис с ним до трех ночи.
Спасибо за ваше решение. Разберу досконально ваш код и постараюсь больше так не лажать.

Цитата:
Есть событие ADDED_TO_STAGE
Спасибо, почитал, некоторые люди после инициализации делают ремув, вы не удаляли это событие, т.е. ремув делать не архиважно? или для необходимости удаления этого события должны происходить еще какие-то условия.

Цитата:
для 100 строк у Вас тоже неправильно показывается. Я вижу только верхушку сотой
Это я видимо где-то накосячил, когда переписывал код для примера, в проектике все четко.

Для таскания pimp я использовал такую штуку startDrag, вы же смотрите у курсора. стартДраг мне нравился тем, что я могу схватиться за любую область пимпа и он не будет смещаться к высоте курсора, как это сейчас происходит в вашем примере с моусеУ. Как я заметил startDrag медленнее конструкции MOUSE_MOVE > mouseY или есть еще какие-то другие причины по которым лучше обходиться без использования стартДраг?

Старый 27.07.2011, 18:20
Zolza вне форума Посмотреть профиль Отправить личное сообщение для Zolza Найти все сообщения от Zolza
  № 5  
Ответить с цитированием
Zolza

Регистрация: Jun 2011
Сообщений: 31
Цитата:
Сообщение от BornTOFree Посмотреть сообщение
стартДраг мне нравился тем, что я могу схватиться за любую область пимпа и он не будет смещаться к высоте курсора, как это сейчас происходит в вашем примере с моусеУ.
Пример реализации стартДраг через события мыши без смещения в точку клика.
http://help.adobe.com/ru_RU/as3/dev/...77837179e-8000


Последний раз редактировалось Zolza; 27.07.2011 в 18:21. Причина: не та ссылка
Старый 27.07.2011, 19:00
in4core вне форума Посмотреть профиль Отправить личное сообщение для in4core Найти все сообщения от in4core
  № 6  
Ответить с цитированием
in4core
[+4 06.05.14]
 
Аватар для in4core

Регистрация: Mar 2009
Сообщений: 4,219
Записей в блоге: 14
как вариант мое старое творение , с wolsh докрутками

Код AS3:
package com.in4core.navigation 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.errors.IllegalOperationError;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	/**
	 * ...
	 * @author in4core
	 * Display or Text Object Scroller
	 * use addScroll methods to define Scroller
	 * Version 1.0
	 */
	public final class UIScrollBar 
	{	
		//-----------------DisplayObjectInit-----------//
		/*objects*/
		private var _scroll:Sprite;
		private var _mask:DisplayObject;
		private var _content:DisplayObjectContainer;
		private var _rect:Rectangle;
 
		/*coords*/
		private var _startYScroll:int;
		private var _startYContent:int;
		private var _wayOfScroll:int;
 
		//-----------------TextFieldInit-----------//
 
		/*objects*/
		private var _tscroll:Sprite;
		private var _tf:TextField;
		private var _trect:Rectangle;
 
		/*coords*/
		private var _wayOfTextScroll:int;
 
		/////////////////////////////////////////////////////////////////////
		//!4
		//!  4                       PUBLIC
		//!    4                                                           
		/////////////////////////////////////////////////////////////////////
 
		public function addScrollObject( scroll:Sprite,mask:DisplayObject,content:DisplayObjectContainer,way:int ):void {
 
			this._scroll = scroll;
			this._mask = mask;
			this._content = content;
			this._wayOfScroll = way;
			this._startYScroll = _scroll.y;
			this._startYContent = _content.y;
			this._rect = new Rectangle(_scroll.x, _scroll.y, 0, _wayOfScroll);
 
			/*events*/
			if (!_scroll.stage) throw new IllegalOperationError ( ' Before add Scroll - add your Scroll in DisplayList use addChild ');
 
			_scroll.addEventListener(MouseEvent.MOUSE_DOWN, dragStart);
			_scroll.stage.addEventListener(MouseEvent.MOUSE_UP, dragStop);
 
			trace( 'UIScrollBar-Display : INIT' );
		}
 
		public function addScrollText( tf:TextField , scroll:Sprite , way:int ):void {
 
			this._tscroll = scroll;
			this._tf = tf;
			this._wayOfTextScroll = way;
			this._trect = new Rectangle(_tscroll.x, _tscroll.y, 0, _wayOfTextScroll);
 
			/*events*/
			if (!_tscroll.stage) throw new IllegalOperationError ( ' Before add Scroll - add your Scroll in DisplayList use addChild ');
 
			_tscroll.addEventListener(MouseEvent.MOUSE_DOWN , tdragStart);
			_tscroll.stage.addEventListener(MouseEvent.MOUSE_UP , tdragStop);
 
			trace( 'UIScrollBar-Text : INIT' );
		}
 
		public function destroy():void {
 
			if (_scroll != null ) {
 
				_scroll.stage.removeEventListener(MouseEvent.MOUSE_MOVE, updatePosition);
				_scroll.removeEventListener(MouseEvent.MOUSE_DOWN, dragStart);
				_scroll.stage.removeEventListener(MouseEvent.MOUSE_UP, dragStop);
			}
 
			if (_tscroll != null ) {
 
				_tscroll.removeEventListener(MouseEvent.MOUSE_DOWN , tdragStart);
				_tscroll.stage.removeEventListener(MouseEvent.MOUSE_UP , tdragStop);
				_tscroll.stage.removeEventListener(MouseEvent.MOUSE_MOVE ,updateTextPosition);
			}
 
			trace( 'UIScrollBar : REMOVED' );
 
		}
		/////////////////////////////////////////////////////////////////////
		//!4
		//!  4                       PRIVATE
		//!    4                                                           
		/////////////////////////////////////////////////////////////////////
		private function tdragStart(e:MouseEvent):void {
 
			_tscroll.startDrag(false, _trect);
			_tscroll.stage.addEventListener(MouseEvent.MOUSE_MOVE ,updateTextPosition);
		}
 
		private function tdragStop(e:MouseEvent):void {
 
			_tscroll.stopDrag();
			_tscroll.stage.removeEventListener(MouseEvent.MOUSE_MOVE ,updateTextPosition);
		}
 
		private function dragStart(e:MouseEvent):void {
 
			_scroll.startDrag(false, _rect);
			_scroll.stage.addEventListener(MouseEvent.MOUSE_MOVE, updatePosition);
		}
 
		private function dragStop(e:MouseEvent):void {
 
			_scroll.stopDrag();
			_scroll.stage.removeEventListener(MouseEvent.MOUSE_MOVE, updatePosition);
		}
 
		private function updatePosition (e:MouseEvent):void {
 
			if (_mask.height < _content.height)
 
			{
				//_scroll.mouseEnabled = true;
				_content.y = _startYContent - ( (_content.height - _mask.height) / _wayOfScroll ) * ( _scroll.y - _startYScroll );
			}
 
			else  null//_scroll.mouseEnabled = false; 
 
			//updateVisible();
		}
 
		private function updateTextPosition(e:MouseEvent):void {
 
			_tf.scrollV = Math.round(((_tscroll.y - _trect.y) / _wayOfTextScroll ) * _tf.maxScrollV);
		}
 
		private function updateVisible():void {
 
			if (_mask.height < _content.height) _scroll.visible = true;
			else _scroll.visible = false;
		}
 
	}
 
}
__________________
Марк Tween


Последний раз редактировалось in4core; 27.07.2011 в 19:02.
Старый 27.07.2011, 19:54
Wolsh вне форума Посмотреть профиль Отправить личное сообщение для Wolsh Найти все сообщения от Wolsh
  № 7  
Ответить с цитированием
Wolsh
Нуб нубам
 
Аватар для Wolsh

модератор форума
Регистрация: Jan 2006
Адрес: Бердск, НСО
Сообщений: 6,445
Цитата:
я могу схватиться за любую область пимпа и он не будет смещаться к высоте курсора, как это сейчас происходит в вашем примере с моусеУ
Хм.. А разве у меня "смещается"? Там специально добавлена переменная _grabY - место, за которое схватили пимпу.

Добавлено через 41 минуту
Цитата:
некоторые люди после инициализации делают ремув, вы не удаляли это событие, т.е. ремув делать не архиважно?
Тупо забыл, если честно)) Классик то на коленке писаный, я стремился сохранить Ваш подход (сам так никогда не делал, делал именно отдельные скроллбары) и поэтому не надо его рассматривать как пример идеального решения. Отписка нужна наверно в 90% случаев, а 10% составляют ситуации когда созданный объект то добавляется на сцену, то удаляется с нее – но не уничтожается, а используется повторно; при этом инициализация тоже требуется повторно. В таком случае надо при удалении со сцены также отписываться от всех событий сцены и подписываться заново при добавлении обратно... вобщем, ситуация специфическая и нечастая.
Драг так драг – по мне так это несущественно, просто не люблю его еще с ас2. Получается какое-то масло-масляное – и МАУС_МУВ слушаем, и отдельно драг обрабатывается, при этом происходит гораздо больше проверок и рассчетов – там ведь и координата х смотрится, а обрабатывая движение вручную, мы не делаем лишних вещей. К тому же можно: а) включить жесткий апдейт Event#updateAfterEvent, что сделает движение еще более плавным и красивым, и b) сделать "плавную прокрутку" с использованием Твина или простым "ручным" ускорением, чтобы движок (и соотв. контент) плавно скользил к мыши.. Драг для дизайнеров, и этим все сказано – он такой и только такой, как и симплБуттон и прочие дизайнерские примочки без контроля программистом.
__________________
Reality.getBounds(this);

Старый 27.07.2011, 21:30
BornTOFree вне форума Посмотреть профиль Отправить личное сообщение для BornTOFree Найти все сообщения от BornTOFree
  № 8  
Ответить с цитированием
BornTOFree

Регистрация: Oct 2010
Сообщений: 85
Ребята Zolza и in4core спасибо за поддержку и помощь Оф. хелп на русском, это очень мило и полезно.
Цитата:
Хм.. А разве у меня "смещается"? Там специально добавлена переменная _grabY - место, за которое схватили пимпу.
Мэджик Видимо вы редактировали свой пост после того как я посмотрел ваш пример. Раньше код выглядел иначе.
Цитата:
Получается какое-то масло-масляное – и МАУС_МУВ слушаем, и отдельно драг обрабатывается
Да, действительно, масло-масляное. С updateAfterEvent() дело имел, чисто визуально движение объектов становится более плавным, по сравнению со стартДраг. Ваша политика мне нравится, буду придерживаться вашим советам.
Спасибо вам.

Создать новую тему Ответ Часовой пояс GMT +4, время: 01:16.
Быстрый переход
  « Предыдущая тема | Следующая тема »  
Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


Часовой пояс GMT +4, время: 01:16.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.