DataGrid与页脚

时间:2012-05-23 23:41:26

标签: actionscript-3 flex flash-builder mxml

我搜索一个解决方案,用页脚创建DataGrid,我发现有一些想法用avanced DataGrid来做,但看起来很难。

您是否知道DataGrid上的页脚的简单解决方案。

非常感谢

1 个答案:

答案 0 :(得分:1)

我在昨天遇到dataGrid页脚问题时遇到了这个问题。 从那以后我设法解决了,因为没有答案(我知道这是一个老问题),有人可能仍然需要一个解决方案,我会在这里发布。

最终结果应该是这样的: http://prntscr.com/5cka32

让我们开始吧:

首先提供页脚支持,我们需要创建一个扩展UIComponent的 DataGridFooterBase 类。 向它添加属于mx_internal命名空间的两个属性(visibleColumns:Array和footerItemsChanged:Boolean)(我决定只有系统需要能够看到它们)。

public class DataGridFooterBase extends UIComponent
{
    mx_internal var visibleColumns:Array;
    mx_internal var footerItemsChanged:Boolean;

    public function DataGridFooterBase()
    {
        super();
    }
}

接下来,我们将创建实际的 DataGridFooter 类,它将扩展 DataGridFooterBase 类。 基本上,这个类将接收一个 ICollection dataProvider,其中的对象将显示在页脚中。想象一下这个场景,你有一个网格,其中有关于发票的信息。您需要在金额*价格列下方显示所有发票的总和。 但是,发票可以有不同的货币(欧元和美元),您需要按货币显示总和。这就是为什么我们有一个 ICollection 类型的dataProvider,它将代表行和列。

public class DataGridFooter extends DataGridFooterBase
{
    protected var dataGrid:Grid;
    protected var footerItems:Array=[];
    protected var cachedFooterHeight:Number=0;
    protected var cachedPaddingBottom:Number=0;
    protected var cachedPaddingTop:Number=0;

    private var _dataProvider:Object;

    public var leftOffset:Number=0;
    public var topOffset:Number=0;
    public var rightOffset:Number=0;
    public var bottomOffset:Number=0;

    public function DataGridFooter()
    {
        super();
    }

    public function set dataProvider(value:Object):void
    {
        if (value != null && !(value is ArrayCollection))
            value=new ArrayCollection([value]);
        _dataProvider=value;
        footerItemsChanged=true;
    }

    public function get dataProvider():Object
    {
        return _dataProvider;
    }

    override protected function createChildren():void
    {
        dataGrid=parent as Grid;
    }
}

这是一个基本设置。接下来,我们需要实现 measure() updateDisplayList()方法。 他们将确保一切都很好和整洁。 所以让我们覆盖这两种方法:

override protected function measure():void
{
    super.measure();
    cachedFooterHeight=dataGrid._explicitFooterHeight ? dataGrid.footerHeight : 22;
    cachedPaddingBottom=getStyle("paddingBottom");
    cachedPaddingTop=getStyle("paddingTop");
    measuredHeight=cachedFooterHeight;
}

override protected function updateDisplayList(w:Number, h:Number):void
{
    graphics.clear();
    graphics.beginFill(0xCFCFCF);
    graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
    graphics.endFill();
    graphics.lineStyle(1, 0x696969);
    graphics.moveTo(0, 0);
    graphics.lineTo(unscaledWidth, 0);
    graphics.endFill();
    updateFooterItemsLayout();
}

如果你想知道图形是什么,我用它来为页脚着色,使其与dataGrid行不同。之后我们需要覆盖 commitProperties()方法,在该方法中我们检查dataProvider是否已更改。如果是,我们需要在更新显示列表之前重新绘制所有页脚元素(否则会出现性能问题)

override protected function commitProperties():void
{
    super.commitProperties();
    if (footerItemsChanged)
    {
        footerItemsChanged=false;
        clearListItems();
        var cols:Array=visibleColumns;
        if ((cols && cols.length > 0 || dataGrid.footerVisible))
        {
            if (_dataProvider != null)
            {
                for (var j:int=0; j < _dataProvider.length; j++)
                {
                    addListItems(j, dataProvider.getItemAt(j));
                }
            }
            else
            {
                addListItems(0, null);
            }
        }
    }
}

让我们继续,到目前为止的一切都是准备,现在我们需要实际的方法,将 IListItemRenderer 对象添加到新的页脚中。 那么让我们创建两个方法, addListItems() removeListItems()

private function addListItems(row:int=0, data:Object=null):void
{
    if (footerItems == null)
        return;
    var cols:Array=visibleColumns;
    footerItems[row]=[];
    var rowData:DataGridListData;
    var item:IListItemRenderer;
    var colNum:int=0;
    var column:GridColumn;
    while (cols && colNum < cols.length)
    {
        column=cols[colNum];
        item=ObjectUtil.copy(column.cachedFooterRenderer) as IListItemRenderer;
        if (item == null)
        {
            item=new DataGridItemRenderer();
            item.styleName=column;
            column.cachedFooterRenderer=item;
        }
        var label:String="";
        if (data != null)
        {
            if (column.labelFunction == null)
                label=String(AbcUtils.findValueInObject(data, column.dataField.split(".")));
            else
                label=String(column.labelFunction(data, column));
            if (label == null || label == "null" || label == "NaN")
                label="";
        }
        rowData=new DataGridListData(label, column.dataField, colNum, uid, dataGrid, 0);
        if (item is IDropInListItemRenderer)
            IDropInListItemRenderer(item).listData=rowData;
        item.data=column;
        item.visible=true;
        addChild(DisplayObject(item));
        footerItems[row][colNum]=item;
        colNum++;
    }
}

private function clearListItems():void
{
    if (footerItems == null)
        return;
    for (var rows:int=0; rows < footerItems.length; rows++)
    {
        var cols:Array=footerItems[rows];
        for (var i:int=0; i < cols.length; i++)
        {
            removeChild(DisplayObject(cols[i]));
        }
    }
    footerItems.splice(0, footerItems.length);
}

这两种方法基本上做了什么,它们采用所有可见列并为dataProvider集合中的每个项目创建 DataGridItemRenderer (footerItems [row] [column]),并将它们添加到我们的显示列表中页脚类,或删除它们。我们在此类中需要的最后一个方法将确保所有项目都根据它们“所属”的列正确定位。

private function updateFooterItemsLayout():void
{
    if (_dataProvider == null || footerItems == null || footerItems.length == 0)
        return;
    for (var row:int=0; row < _dataProvider.length; row++)
    {
        var cols:Array=visibleColumns;
        var item:IListItemRenderer;
        var colNum:int=0;
        var ww:Number=0;
        var xx:Number=0;
        var column:GridColumn;
        while (cols && colNum < cols.length)
        {
            column=cols[colNum];
            item=footerItems[row][colNum];
            item.explicitWidth=ww=column.width;
            UIComponentGlobals.layoutManager.validateClient(item, true);
            item.setActualSize(ww, item.getExplicitOrMeasuredHeight());
            if (row == 0)
                item.move(xx, cachedPaddingTop);
            else
                item.move(xx, item.height * row + cachedPaddingTop);
            xx+=ww;
            colNum++;
        }
    }
}

基本上就是这样。现在我们需要调整DataGrid和DataGridColumn类来连接我们的新Footer类。


让我们继续使用 DataGrid 类。我们需要创建一个新的Grid类,它将扩展DataGrid类。

public class Grid extends DataGrid
{
    public function Grid()
    {
        super();
    }

    //==== footer specific stuff =======
    protected var footer:DataGridFooterBase;
    mx_internal var footerClass:Class=DataGridFooter;
    private var _enableFooter:Boolean;
    private var _footerHeight:int=22;
    mx_internal var _explicitFooterHeight:Boolean;

    mx_internal function get dataGridFooter():DataGridFooterBase
    {
        return footer;
    }

    [Bindable("enableFootersChanged")]
    [Inspectable(category="General", defaultValue="false")]
    public function get enableFooters():Boolean
    {
        return _enableFooter;
    }

    public function set enableFooters(value:Boolean):void
    {
        if (value == _enableFooter)
            return;
        _enableFooter=enabled;
        invalidateDisplayList();
        dispatchEvent(new Event("enableFootersChanged"));
    }

    mx_internal function get footerVisible():Boolean
    {
        return enableFooters && (footerHeight > 0) && footer != null;
    }

    [Bindable("resize")]
    [Inspectable(category="General", defaultValue="22")]
    public function get footerHeight():Number
    {
        return _footerHeight;
    }

    public function set footerHeight(value:Number):void
    {
        _footerHeight=value;
        _explicitFooterHeight=true;
        invalidateDisplayList();
    }

    public function setFooterValues(value:Object):void
    {
        if (footer != null)
            DataGridFooter(footer).dataProvider=value;
    }
    //==========================================

    override protected function createChildren():void
    {
        super.createChildren();
        if (enableFooters && footer == null)
        {
            footer=new footerClass();
            addChild(footer);
        }
    }

    override public function invalidateDisplayList():void
    {
        super.invalidateDisplayList();
        if (footer != null)
        {
            footer.invalidateSize();
            footer.invalidateDisplayList();
        }
    }

    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        if (footer != null)
        {
            footer.visibleColumns=visibleColumns;
            footer.invalidateSize();
            footer.validateNow();
        }
        if (footerVisible && verticalScrollBar && verticalScrollBar.visible)
        {
            var maxHeight:Number=this.verticalScrollBar.height - this.footer.height;
            verticalScrollBar.setActualSize(verticalScrollBar.width, maxHeight);
        }
    }

    override protected function adjustListContent(unscaledWidth:Number=-1, unscaledHeight:Number=-1):void
    {
        super.adjustListContent(unscaledWidth, unscaledHeight);
        var refY:Number=header.height;
        var additionalReservedHeight:Number=0;
        additionalReservedHeight+=footerVisible ? footerHeight : 0;
        listContent.setActualSize(listContent.width, listContent.height - additionalReservedHeight);
        refY+=listContent.height;
        if (footerVisible)
        {
            footer.move(listContent.x, refY);
            footer.setActualSize(listContent.width, footerHeight);
            refY+=footer.height;
        }
    }

    override protected function measure():void
    {
        super.measure();
        var additionalReservedHeight:Number=0;
        if (enableFooters)
            additionalReservedHeight+=footerHeight;
        this.measuredHeight=header.getExplicitOrMeasuredHeight() + additionalReservedHeight + (rowHeight * rowCount) + viewMetrics.bottom + viewMetrics.top;
        this.measuredMinHeight=header.getExplicitOrMeasuredHeight() + additionalReservedHeight + (rowHeight * rowCount) + viewMetrics.bottom + viewMetrics.top;
    }
}

我相信这个课程或多或少是自我解释的。要将值设置为Footer,您需要使用 setFooterValues()功能,您可以使用单个对象或 ICollection 对象。你需要做的另一件事,如果你希望你的页脚中有多行,你需要在页脚中明确设置 footerHeight 属性(或修改 measure()方法类根据集合中的项目数自动缩放。)

我们最不需要的是修改 DataGridColumn 类,为 IListItemRenderer 添加存储空间。 这是:

public class GridColumn extends DataGridColumn
{
    mx_internal var cachedFooterRenderer:IListItemRenderer;

    public function GridColumn(columnName:String=null)
    {
        super(columnName);
    }
}

就是这样。希望这有助于某人,而不是TL; DR; :) 欢呼声。