Класс FlowBox из flexlib

· На чтение уйдёт 4 минуты · (686 слов)

Есть такая замечательная библиотека для программирования с применением Adobe Flex, под названием flexlib. Разумеется, к ней есть документация, которую можно найти на страничке проекта.

Но я хотел бы написать об использовании конкретного класса FlowBox, и о совместимости его с недавно вышедшим Flex 3. (В продолжении статьи). А вот - полный список компонентов, входящих во FlexLib.

FlowBox - это такой Box, в который объекты добавляются и размещаются в нем в зависимости от их размеров. Например, в первой строчке может быть 10 узких объектов, а во второй - 1 широкий. Этот объект используется для допзоны в Берсерк-Онлайн. Зачем это надо? Если мы точно знаем, что ширина контейнера 200, а ширина всех его детей по 100, - мы конечно можем использовать Box, указав, что в каждой строчке нужно размещать по 2 объекта. Но если мы не знаем ни ширину контейнера, ни ширину детей - FlowBox нас спасет.

Но - самое большое разочарование постигает нас неожиданно. Дело в том, что если скин (borderSkin) задает собственные EdgeMetrics, то они учитываются. Что в контексте Flex 3 - может быть некорректно (если borderSkin объекта является наследником RectangularBorder) - так как поддержка RectangularBorder есть внутри самого Flex (геттер borderMetrics класса Container), но возможно корректно в контексте Flex 2.

Однако, если исключить из FlowLayout.as все упоминания про viewMetrics и borderMetrics, все становится нормально. Вот подкорректированный мной метод doLayout (не будет корректно работать с бордерами на основе IBorder (а не IRectangularBorder) и во Flex 2, так что на решение проблемы я не претендую).

[geshi lang=Actionscript]
private function doLayout(unscaledWidth:Number, moveChildren:Boolean):void
{
	var vm:EdgeMetrics = target.viewMetricsAndPadding;
	
	var hAlign:Number = getHorizontalAlignValue();
	var vAlign:Number = getVerticalAlignValue();
	var hGap:Number = target.getStyle( "horizontalGap" );
	var vGap:Number = target.getStyle( "verticalGap" );
	var len:Number = target.numChildren;
	
	var currentRowChildren:Array = new Array;
	var currentRowHeight:Number = 0;
	var currentRowY:Number = 0; // dirty hack by baron
	var currentRowLastX:Number = 0; // dirty hack by baron
	
	var child:IFlexDisplayObject;
	var tmpChild:IFlexDisplayObject;
	var rowExcessSpace:Number;
	var top:Number;
	
	var maxX:Number;
	var maxY:Number;
	
	var paddingRight:Number = target.getStyle("paddingRight"); // dirty hack by baron
	var paddingLeft:Number = target.getStyle("paddingLeft"); // dirty hack by baron
	
	for ( var i:int = 0; i < len; i++ )
	{
		child = IFlexDisplayObject( target.getChildAt( i ) );
		
		if(child is UIComponent && !UIComponent(child).includeInLayout) {
			continue;
		}
		
		// If the child can't be placed in the current row....
		if ( currentRowLastX + child.width > unscaledWidth - paddingRight )
		{
			currentRowLastX -= hGap;
			
			rowExcessSpace = unscaledWidth - paddingRight - currentRowLastX;
			rowExcessSpace *= hAlign;
			currentRowLastX = rowExcessSpace == 0 ? paddingLeft : rowExcessSpace;
							
			// Go back through the row and adjust the children for
			// their vertical and horizontal align values
			for ( var j:int = 0; j < currentRowChildren.length; j++ )
			{
				tmpChild = currentRowChildren[ j ];
				
				top = ( currentRowHeight - tmpChild.height ) * vAlign;
				if(moveChildren) {
					tmpChild.move( Math.floor( currentRowLastX ), currentRowY + Math.floor( top ) );
				}
				currentRowLastX += tmpChild.width + hGap;
			}
			
			// Start a new row
			currentRowY += currentRowHeight + vGap;
			currentRowLastX = paddingLeft;
			currentRowHeight = 0;
			currentRowChildren = [];	
			
		}
		
		// Don't actually move the child yet because that'd done when we
		// "finish" a row
		//child.move( currentRowLastX, currentRowY );
		
		// Move on to the next x location in the row
		currentRowLastX += child.width + hGap;
		
		// Add the child to the current row so we can adjust the
		// coordinates based on vAlign and hAlign
		currentRowChildren.push( child );
		
		// The largest child height in the row is the height for the
		// entire row
		currentRowHeight = Math.max( child.height, currentRowHeight );
	}
	
	
	// Done laying out the children, finish up the children that
	// are in the last row -- adjust the children for
	// their vertical and horizontal align values
	
	//remove the single extra padding we have
	currentRowLastX -= hGap;
	
	rowExcessSpace = unscaledWidth - paddingRight - currentRowLastX;
	rowExcessSpace *= hAlign;
	currentRowLastX = rowExcessSpace == 0 ? paddingLeft : rowExcessSpace;
	
	for ( j = 0; j < currentRowChildren.length; j++ )
	{
		tmpChild = currentRowChildren[ j ];
		top = ( currentRowHeight - tmpChild.height ) * vAlign;
		if(moveChildren) {
			tmpChild.move( Math.floor( currentRowLastX ), currentRowY + Math.floor( top ) );
		}
		currentRowLastX += hGap + tmpChild.width;
	}
	
	if(!moveChildren) {
		target.measuredHeight  = currentRowY + currentRowHeight + vm.bottom + vm.top;
	}
}[/geshi]
Полезное