Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Actionscript 3 具有不同列计数的列表_Actionscript 3_Apache Flex_Flex4 - Fatal编程技术网

Actionscript 3 具有不同列计数的列表

Actionscript 3 具有不同列计数的列表,actionscript-3,apache-flex,flex4,Actionscript 3,Apache Flex,Flex4,正如图片所示(这是由PhotoShop绘制的,尚未实现),我想实现一个类似这样的列表。它有不同的列计数,比如第一行只有一个项,其他行有两个项。我尝试使用ItemRenderFunction检测不同的项(第一行视为渲染器a,其他行视为另一个渲染器B),但它不起作用。无论何时要更改现有组件的定义行为,请始终首先检查是否可以解决蒙皮问题。这是Flex中一个非常强大的功能,在这种情况下也可以提供解决方案 那么,让我们开始吧,假设您已经有了列表,您只需要创建一个自定义皮肤,它将数据提供程序“拆分”为两部分


正如图片所示(这是由PhotoShop绘制的,尚未实现),我想实现一个类似这样的
列表。它有不同的列计数,比如第一行只有一个项,其他行有两个项。我尝试使用
ItemRenderFunction
检测不同的项(第一行视为渲染器a,其他行视为另一个渲染器B),但它不起作用。

无论何时要更改现有组件的定义行为,请始终首先检查是否可以解决蒙皮问题。这是Flex中一个非常强大的功能,在这种情况下也可以提供解决方案

那么,让我们开始吧,假设您已经有了列表,您只需要创建一个自定义皮肤,它将数据提供程序“拆分”为两部分,第一个项目和所有其他项目。那么,让我们假设我们有这个初始设置:

<fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        private var c:ArrayCollection = new ArrayCollection([
            "String 1",
            "String 2",
            "String 3",
            "String 4",
            "String 5",
            "String 6",
            "String 7",
            "String 8",
            "String 9",
            "String 10",
            "String 11",
            "String 12",
            "String 13",
            "String 14",
            "String 15"]);
    ]]>
</fx:Script>

<s:List skinClass="CustomSkinList" dataProvider="{c}" />
这里是我们必须进行更改的地方,以便使第一个元素以不同的方式渲染。我们需要做的只是添加另一个数据组,以自定义方式呈现第一个元素(这当然意味着使用自定义项呈现器)。现在,我们的滚动条如下所示:

<s:Scroller left="0"
            top="0"
            right="0"
            bottom="0"
            id="scroller"
            minViewportInset="1"
            hasFocusableChildren="false">
    <!--- @copy spark.components.SkinnableDataContainer#dataGroup -->
    <s:VGroup width="100%" height="100%">

        <s:DataGroup id="firstItemDataGroup"
                     width="100%"
                     itemRenderer="CustomItemRenderer"
                     height="20">
            <s:layout>
                <s:VerticalLayout />
            </s:layout>
        </s:DataGroup>

        <s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
            <s:layout>
                <!--- The default layout is vertical and measures at least for 5 rows.
                When switching to a different layout, HorizontalLayout for example,
                make sure to adjust the minWidth, minHeight sizes of the skin -->
                <s:TileLayout horizontalAlign="center" requestedColumnCount="2" />
            </s:layout>
        </s:DataGroup>
    </s:VGroup>
</s:Scroller>
<s:List dataProvider="{dp}" height="300">
    <s:layout>
        <l:MyCustomLayout />
    </s:layout>
</s:List>
添加的只是“if”块和一个名为dataGroupProvider的私有变量。这是因为我们将在updateDisplayList()方法中将新的dataProvider(从第二个元素开始)设置为dataGroup元素。下面是它的外观:

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            if (getStyle("borderVisible") == true)
            {
                border.visible = true;
                background.left = background.top = background.right = background.bottom = 1;
                scroller.minViewportInset = 1;
            }
            else
            {
                border.visible = false;
                background.left = background.top = background.right = background.bottom = 0;
                scroller.minViewportInset = 0;
            }

            // Here we assign the new data provider to the dataGroup element
            if (dataGroupProvider)
                dataGroup.dataProvider = dataGroupProvider;

            borderStroke.color = getStyle("borderColor");
            borderStroke.alpha = getStyle("borderAlpha");

            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }
总之,只要为列表元素创建一个自定义外观,我们就可以使用两个容器以不同于其他元素的方式呈现第一项。您不应该低估Flex蒙皮的威力:)


希望这有帮助。祝你今天愉快

无论何时要更改现有组件的已定义行为,请始终首先检查是否可以解决蒙皮问题。这是Flex中一个非常强大的功能,在这种情况下也可以提供解决方案

那么,让我们开始吧,假设您已经有了列表,您只需要创建一个自定义皮肤,它将数据提供程序“拆分”为两部分,第一个项目和所有其他项目。那么,让我们假设我们有这个初始设置:

<fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        private var c:ArrayCollection = new ArrayCollection([
            "String 1",
            "String 2",
            "String 3",
            "String 4",
            "String 5",
            "String 6",
            "String 7",
            "String 8",
            "String 9",
            "String 10",
            "String 11",
            "String 12",
            "String 13",
            "String 14",
            "String 15"]);
    ]]>
</fx:Script>

<s:List skinClass="CustomSkinList" dataProvider="{c}" />
这里是我们必须进行更改的地方,以便使第一个元素以不同的方式渲染。我们需要做的只是添加另一个数据组,以自定义方式呈现第一个元素(这当然意味着使用自定义项呈现器)。现在,我们的滚动条如下所示:

<s:Scroller left="0"
            top="0"
            right="0"
            bottom="0"
            id="scroller"
            minViewportInset="1"
            hasFocusableChildren="false">
    <!--- @copy spark.components.SkinnableDataContainer#dataGroup -->
    <s:VGroup width="100%" height="100%">

        <s:DataGroup id="firstItemDataGroup"
                     width="100%"
                     itemRenderer="CustomItemRenderer"
                     height="20">
            <s:layout>
                <s:VerticalLayout />
            </s:layout>
        </s:DataGroup>

        <s:DataGroup id="dataGroup" itemRenderer="spark.skins.spark.DefaultItemRenderer">
            <s:layout>
                <!--- The default layout is vertical and measures at least for 5 rows.
                When switching to a different layout, HorizontalLayout for example,
                make sure to adjust the minWidth, minHeight sizes of the skin -->
                <s:TileLayout horizontalAlign="center" requestedColumnCount="2" />
            </s:layout>
        </s:DataGroup>
    </s:VGroup>
</s:Scroller>
<s:List dataProvider="{dp}" height="300">
    <s:layout>
        <l:MyCustomLayout />
    </s:layout>
</s:List>
添加的只是“if”块和一个名为dataGroupProvider的私有变量。这是因为我们将在updateDisplayList()方法中将新的dataProvider(从第二个元素开始)设置为dataGroup元素。下面是它的外观:

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            if (getStyle("borderVisible") == true)
            {
                border.visible = true;
                background.left = background.top = background.right = background.bottom = 1;
                scroller.minViewportInset = 1;
            }
            else
            {
                border.visible = false;
                background.left = background.top = background.right = background.bottom = 0;
                scroller.minViewportInset = 0;
            }

            // Here we assign the new data provider to the dataGroup element
            if (dataGroupProvider)
                dataGroup.dataProvider = dataGroupProvider;

            borderStroke.color = getStyle("borderColor");
            borderStroke.alpha = getStyle("borderAlpha");

            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }
总之,只要为列表元素创建一个自定义外观,我们就可以使用两个容器以不同于其他元素的方式呈现第一项。您不应该低估Flex蒙皮的威力:)


希望这有帮助。祝你今天愉快

这个问题最干净的解决方案是创建一个自定义布局(我们在评论中讨论了Romi的解决方案最终会导致太多问题)。然而,这通常不是一件容易的事情

我会给你一个大概的草图,这个自定义布局可能看起来像什么,所以你可以用它作为一个起点来创建一个完全符合你需要的布局。 要创建自定义布局,必须子类化
BaseLayout
,重写并实现其
updateDisplayList
measure
方法

为了使事情更简单(并且为了不在这里转储500行代码),我在这个示例中使用了一些硬编码变量。它假设始终有两列,第一项始终为200x200 px,其他项始终为100x100 px。没有水平间隙或垂直间隙。
其结果当然是,您只能对这个特定的列表和这些特定的ItemRenders使用这个自定义布局(现在就是这样)。如果你想让它更通用,你必须做更多的计算

但现在,对于代码:

public class MyCustomLayout extends LayoutBase {

    //hardcoded variables
    private var columnCount:int = 2;

    private var bigTileWidth:Number = 200;
    private var bigTileHeight:Number = 200;
    private var smallTileWidth:Number = 100;
    private var smallTileHeight:Number = 100;

    override public function updateDisplayList(width:Number, height:Number):void {
        var layoutTarget:GroupBase = target;
        if (!layoutTarget) return;

        var numElements:int = layoutTarget.numElements;
        if (!numElements) return;

        //position and size the first element
        var el:ILayoutElement = useVirtualLayout ? 
            layoutTarget.getVirtualElementAt(0) : layoutTarget.getElementAt(0);
        el.setLayoutBoundsSize(bigTileWidth, bigTileHeight);
        el.setLayoutBoundsPosition(0, 0);

        //position & size the other elements in 2 columns below the 1st element
        for (var i:int=1; i<numElements; i++) {
            var x:Number = smallTileWidth  * ((i-1) % 2);
            var y:Number = smallTileHeight * Math.floor((i-1) / 2) + bigTileHeight;

            el = useVirtualLayout ? 
                layoutTarget.getVirtualElementAt(i) : 
                layoutTarget.getElementAt(i);
            el.setLayoutBoundsSize(smallTileWidth, smallTileHeight);
            el.setLayoutBoundsPosition(x, y);
        }

        //set the content size (necessary for scrolling)
        layoutTarget.setContentSize(
            layoutTarget.measuredWidth, layoutTarget.measuredHeight
        );
    }

    override public function measure():void {
        var layoutTarget:GroupBase = target;
        if (!layoutTarget) return;

        var rowCount:int = Math.ceil((layoutTarget.numElements - 1) / 2);

        //measure the total width and height
        layoutTarget.measuredWidth = layoutTarget.measuredMinWidth = 
            Math.max(smallTileWidth * columnCount, bigTileWidth);
        layoutTarget.measuredHeight = layoutTarget.measuredMinHeight = 
            bigTileHeight + smallTileHeight * rowCount;
    }

}
公共类MyCustomLayout扩展了LayoutBase{
//硬编码变量
私有变量columnCount:int=2;
私有变量bigTileWidth:Number=200;
私有变量bigTileHeight:Number=200;
私有变量smallTileWidth:Number=100;
私有变量smallTileHeight:Number=100;
重写公共函数updateDisplayList(宽度:数字,高度:数字):无效{
var layoutTarget:GroupBase=目标;
如果(!layoutTarget)返回;
var numElements:int=layoutTarget.numElements;
如果(!numElements)返回;
//定位并调整第一个元素的大小
变量el:ILayoutElement=useVirtualLayout?
layoutTarget.getVirtualElementAt(0):layoutTarget.getElementAt(0);
el.setLayoutBoundsSize(bigTileWidth,bigTileHeight);
el.setLayoutBoundsPosition(0,0);
//在第一个元素下方的2列中定位其他元素并调整其大小

对于(var i:int=1;i这个问题最干净的解决方案是创建一个自定义布局(我们在评论中讨论了Romi的解决方案最终会导致太多问题)。然而,这通常不是一件容易的事情

我会给你一个大概的草图,这个自定义布局可能看起来像什么,所以你可以用它作为一个起点来创建一个完全符合你需要的布局。 要创建自定义布局,必须子类化
BaseLayout
,重写并实现其
updateDisplayList
measure
方法

为了使事情变得更简单(并且为了不在这里转储500行代码),我在本例中使用了一些硬编码变量。它假设总是有两列,第一个项目总是200x200 px,其他项目总是100x100 px。没有水平间隙或垂直间隙。