-1

Evtim はすばらしい顧客であるFlowLayoutを作成し、Maxim も優れた顧客である Horizo​​ntal Multiline Layoutを持っていますが、ドラッグドロップをサポートしていません。ドラッグ アンド ドロップをサポートする LayoutBase を拡張する顧客レイアウトを定義する場合、ユーザーはどの関数を実装またはオーバーライドする必要がありますか?

4

1 に答える 1

1

以下は、Maxim のHorizo​​ntal Multiline Layouyに基づく私の顧客レイアウトです。

public class HorizontalMultilineLayout extends LayoutBase {
        private var _rowCount:int = -1;
        private var _columnCount:int = -1;

        //container width
        private var lastWidth:Number = -1;

        private var _horizontalGap:Number = 6;

        public function get horizontalGap():Number
        {
            return _horizontalGap;
        }

        public function set horizontalGap(value:Number):void
        {
            if (value == _horizontalGap)
                return;

            _horizontalGap = value;
            invalidateTargetSizeAndDisplayList();
        }

        private var _verticalGap:Number = 6;

        public function get verticalGap():Number
        {
            return _verticalGap;
        }

        public function set verticalGap(value:Number):void
        {
            if (value == _verticalGap)
                return;

            _verticalGap = value;
            invalidateTargetSizeAndDisplayList();
        }

        private var _verticalAlign:String = VerticalAlign.TOP;

        [Inspectable(category="General", enumeration="top,bottom,middle", defaultValue="top")]
        public function get verticalAlign():String
        {
            return _verticalAlign;
        }

        public function set verticalAlign(value:String):void
        {
            if (_verticalAlign == value)
                return;

            _verticalAlign = value;
            invalidateTargetSizeAndDisplayList();
        }

        private var _paddingLeft:Number = 0;

        public function get paddingLeft():Number
        {
            return _paddingLeft;
        }

        public function set paddingLeft(value:Number):void
        {
            if (_paddingLeft == value)
                return;

            _paddingLeft = value;
            invalidateTargetSizeAndDisplayList();
        }    

        private var _paddingRight:Number = 0;

        public function get paddingRight():Number
        {
            return _paddingRight;
        }

        public function set paddingRight(value:Number):void
        {
            if (_paddingRight == value)
                return;

            _paddingRight = value;
            invalidateTargetSizeAndDisplayList();
        }    

        private var _paddingTop:Number = 0;

        public function get paddingTop():Number
        {
            return _paddingTop;
        }

        public function set paddingTop(value:Number):void
        {
            if (_paddingTop == value)
                return;

            _paddingTop = value;
            invalidateTargetSizeAndDisplayList();
        }    

        private var _paddingBottom:Number = 0;

        public function get paddingBottom():Number
        {
            return _paddingBottom;
        }

        public function set paddingBottom(value:Number):void
        {
            if (_paddingBottom == value)
                return;

            _paddingBottom = value;
            invalidateTargetSizeAndDisplayList();
        }    

        override public function measure():void
        {
            if (lastWidth == -1) {
                return;
            }

            var measuredWidth:Number = 0;
            var measuredMinWidth:Number = 0;
            var measuredHeight:Number = 0;
            var measuredMinHeight:Number = 0;

            var layoutTarget:GroupBase = target;
            var n:int = layoutTarget.numElements;
            var element:ILayoutElement;
            var i:int;
            var width:Number = layoutTarget.explicitWidth;
            if (isNaN(width) && lastWidth != -1)
                width = lastWidth;
            if (isNaN(width)) // width is not defined by parent or user
            {
                // do not specify measuredWidth and measuredHeight to real
                // values because in fact we can layout at any width or height
                for (i = 0; i < n; i++)
                {
                    element = useVirtualLayout ? layoutTarget.getVirtualElementAt(i) : layoutTarget.getElementAt(i);
                    if (!element || !element.includeInLayout)
                        continue;

                    measuredWidth = Math.ceil(element.getPreferredBoundsWidth());
                    measuredHeight = Math.ceil(element.getPreferredBoundsHeight());
                    break;
                }
                measuredMinWidth = measuredWidth;
                measuredMinHeight = measuredHeight;
            }
            else
            {
                // calculate lines based on width
                var currentLineWidth:Number = 0;
                var currentLineHeight:Number = 0;
                var lineNum:int = 1;
                for (i = 0; i < n; i++)
                {
                    element = useVirtualLayout ? layoutTarget.getVirtualElementAt(i) : layoutTarget.getElementAt(i);
                    if (!element || !element.includeInLayout)
                        continue;

                    var widthWithoutPaddings:Number = width - _paddingLeft - _paddingRight;
                    var elementWidth:Number = Math.ceil(element.getPreferredBoundsWidth());
                    if (currentLineWidth == 0 || 
                        currentLineWidth + _horizontalGap + elementWidth <= widthWithoutPaddings)
                    {
                        currentLineWidth += elementWidth + (currentLineWidth == 0 ? 0 : _horizontalGap);
                        currentLineHeight = Math.max(currentLineHeight, Math.ceil(element.getPreferredBoundsHeight()));
                    }
                    else
                    {
                        measuredHeight += currentLineHeight;

                        lineNum++;
                        currentLineWidth = elementWidth;
                        currentLineHeight = Math.ceil(element.getPreferredBoundsHeight());
                    }
                }
                measuredHeight += currentLineHeight;
                if (lineNum > 1)
                    measuredHeight += _verticalGap * (lineNum - 1);

                // do not set measuredWidth to real value because really we can  
                // layout at any width
                for (i = 0; i < n; i++)
                {
                    element = useVirtualLayout ? layoutTarget.getVirtualElementAt(i) : layoutTarget.getElementAt(i);
                    if (!element || !element.includeInLayout)
                        continue;

                    measuredWidth =
                        measuredMinWidth = Math.ceil(element.getPreferredBoundsWidth());
                    break;
                }
                measuredMinHeight = measuredHeight;
            }

            layoutTarget.measuredWidth = measuredWidth + _paddingLeft + _paddingRight;
            layoutTarget.measuredMinWidth = measuredMinWidth + _paddingLeft + _paddingRight;
            layoutTarget.measuredHeight = measuredHeight + _paddingTop + _paddingBottom;
            layoutTarget.measuredMinHeight = measuredMinHeight + _paddingTop + _paddingBottom;
        }

        override public function updateDisplayList(width:Number, height:Number):void
        {
            resetRowAndColumn();
            var layoutTarget:GroupBase = target;
            var n:int = layoutTarget.numElements;
            var element:ILayoutElement;
            var i:int;
            // calculate lines based on width
            var x:Number = _paddingLeft;
            var y:Number = _paddingTop;
            var maxLineHeight:Number = 0;
            var elementCounter:int = 0;
            var positions:Vector.<Point> = new Vector.<Point>();
            for (i = 0; i < n; i++)
            {
                element = useVirtualLayout ? layoutTarget.getVirtualElementAt(i) : layoutTarget.getElementAt(i);
                if (!element || !element.includeInLayout)
                    continue;

                var elementWidth:Number = Math.ceil(element.getPreferredBoundsWidth());
                if (x == _paddingLeft || x + _horizontalGap + elementWidth <= width - _paddingRight) {
                    if (elementCounter > 0)
                        x += _horizontalGap;
                    positions[i] = new Point(x, y);
                    element.setLayoutBoundsSize(NaN, NaN);
                    maxLineHeight = Math.max(maxLineHeight, Math.ceil(element.getPreferredBoundsHeight()));
                    //calculate column count
                    if(!startNewLine) {
                        _columnCount++;
                    }
                }else {
                    startNewLine = true;
                    _rowCount++;
                    x = _paddingLeft;
                    y += _verticalGap + maxLineHeight;
                    maxLineHeight = Math.ceil(element.getPreferredBoundsHeight());
                    positions[i] = new Point(x, y);
                    element.setLayoutBoundsSize(NaN, NaN);
                }
                x += elementWidth;
                elementCounter++;
            }

            // verticalAlign and setLayoutBoundsPosition() for elements
            var yAdd:Number = 0;
            var yDifference:Number = height - (y + maxLineHeight + _paddingBottom);
            if (_verticalAlign == VerticalAlign.MIDDLE)
                yAdd = Math.round(yDifference / 2);
            else if (_verticalAlign == VerticalAlign.BOTTOM)
                yAdd = Math.round(yDifference);
            for (i = 0; i < n; i++)
            {
                element = useVirtualLayout ? layoutTarget.getVirtualElementAt(i) : layoutTarget.getElementAt(i);
                if (!element || !element.includeInLayout)
                    continue;
                var point:Point = positions[i];
                point.y += yAdd;
                element.setLayoutBoundsPosition(point.x, point.y);
            }

            // if width changed then height will change too - remeasure
            if (lastWidth == -1 || lastWidth != width)
            {
                lastWidth = width;
                invalidateTargetSizeAndDisplayList();
            }
            //trace("rowCount: ---", _rowCount, " ---columnCount: ----", _columnCount);
        }

        private var startNewLine:Boolean = false;

        private function resetRowAndColumn():void {
            var num:int = target.numElements;
            if(num >0) {
                _rowCount = 1;
                _columnCount = 0;
            } else {
                _rowCount = _columnCount = 0;
            }
            startNewLine = false;
        }

        private function invalidateTargetSizeAndDisplayList():void
        {
            var g:GroupBase = target;
            if (!g)
                return;

            g.invalidateSize();
            g.invalidateDisplayList();
        }

        private function calculateDropCellIndex(x:Number, y:Number):Array {
            var xStart:Number = x - paddingLeft;
            var yStart:Number = y - paddingTop;
            var column:int = Math.floor(xStart / (columnWidth + _horizontalGap));
            var row:int = Math.floor(yStart / (rowHeight + _verticalGap));

            // Check whether x is closer to left column or right column:
            var midColumnLine:Number;
            var midRowLine:Number;

            midColumnLine = (column + 1) * (columnWidth + _horizontalGap) - _horizontalGap - columnWidth / 2; 

            // Mid-line is at the middle of the gap between the rows
            midRowLine = (row + 1) * (rowHeight + _verticalGap) - _verticalGap / 2;  

            if (xStart > midColumnLine)
                column++;
            if (yStart > midRowLine)
                row++;

            // Limit row and column, if any one is too far from the drop location
            // And there is white space
            if (column > _columnCount || row > _rowCount)
            {
                row = _rowCount;
                column = _columnCount;
            }

            if (column < 0)
                column = 0;
            if (row < 0)
                row = 0;

            if (row >= _rowCount)
                row = _rowCount - 1;

            return [row, column];
        }

        override protected function calculateDropIndex(x:Number, y:Number):int {
            var result:Array = calculateDropCellIndex(x, y);
            var row:int = result[0]; 
            var column:int = result[1]; 
            var index:int = row * _columnCount + column;
            var count:int = target.numElements;

            if (index > count) {
                index = count;
            }

            return index;
        }

        private function get columnWidth():Number {
            return typicalLayoutElement.getLayoutBoundsWidth();
        }

        private function get rowHeight():Number {
            return typicalLayoutElement.getLayoutBoundsHeight();
        }

        //NOTE:we do NOT use contentWidth
        override protected function calculateDropIndicatorBounds(dropLocation:DropLocation):Rectangle {
            var result:Array = calculateDropCellIndex(dropLocation.dropPoint.x, dropLocation.dropPoint.y);
            var row:int = result[0]; 
            var column:int = result[1]; 

            var count:int = target.numElements;

            // The last row may be only partially full,
            // don't drop beyond the last column.
            if (row * _columnCount + column > count)
                column = count - (_rowCount - 1) * _columnCount;

            var x:Number;
            var y:Number;
            var dropIndicatorElement:IVisualElement;
            var emptySpace:Number; // empty space between the elements

            // Start with the dropIndicator dimensions, in case it's not 
            // an IVisualElement
            var width:Number = dropIndicator.width;
            var height:Number = dropIndicator.height;

            emptySpace = (0 < _horizontalGap ) ? _horizontalGap : 0; 
            var emptySpaceLeft:Number = column * (columnWidth + _horizontalGap) - emptySpace;

            // Special case - if we have negative gap and we're the last column,
            // adjust the emptySpaceLeft
            if (_horizontalGap < 0 && (column == _columnCount || count == dropLocation.dropIndex))
                emptySpaceLeft -= _horizontalGap;

            width = emptySpace;
            height = rowHeight;
            // Special case - if we have negative gap and we're not the last
            // row, adjust the height
            if (_verticalGap < 0 && row < _rowCount - 1)
                height += _verticalGap + 1;

            if (dropIndicator is IVisualElement)
            {
                dropIndicatorElement = IVisualElement(dropIndicator);
                width = Math.max(Math.min(width,
                    dropIndicatorElement.getMaxBoundsWidth(false)),
                    dropIndicatorElement.getMinBoundsWidth(false));
            }

            x = emptySpaceLeft + Math.round((emptySpace - width) / 2) + paddingLeft;
            // Allow 1 pixel overlap with container border
            //x = Math.max(-1, Math.min(target.contentWidth - width + 1, x));
            //NOTE:we do NOT use contentWidth
            x = Math.max(-1, Math.min(target.width - width + 1, x));
            y = row * (rowHeight + _verticalGap) + paddingTop;
            return new Rectangle(x, y, width, height);
        }
 }
于 2013-04-22T03:14:59.040 に答える