如何在flex中组合渲染器?

时间:2010-12-03 17:00:45

标签: flex actionscript-3 flex4 itemrenderer

我正在尝试创建一个包含x按钮的通用列表控件,以便用户可以通过单击x按钮从列表中删除项目。但是,此列表控件需要支持项呈示器,同时仍然标准化放置在x按钮旁边的项目的布局。

所以我认为最好的方法是扩展列表控件并使用绘制x按钮的渲染器,并将其与用户提供的渲染器相结合。不幸的是我无法弄清楚如何做到这一点。

我尝试从IFactory接口覆盖newInstance方法并使用它来创建包含我的按钮的HBox并从用户提供的渲染器插入newInstance结果,但是它不完整。它显示为我所期望的,但鼠标悬停效果仅适用于用户提供的渲染器部分,而不是我的自定义渲染器制作的整个HBox。

关于此主题的Flex文档中似乎有很多缺失的细节。

我在Action Script 3中完成了所有这些。

3 个答案:

答案 0 :(得分:4)

我不认为这样做的方法是扩展List控件。相反,我会尝试创建我的自定义itemRenderer,然后根据需要扩展它。实现这一目标的一种方法可以是:

  • 创建自己的SkinnableComponent,它实现了IItemRenderer或IDataRenderer。
  • 添加组件所需的部分(删除按钮)和您需要的行为(例如:deleteButton click handler)
  • 扩展您创建的组件以创建具体的渲染器。

编辑:添加了示例

这是一个简单的示例,说明如何创建一个扩展SkinnableComponent并实现IDataRenderer的itemRenderer。它支持2种状态,正常和悬停。请注意,在Flex中创建ItemRenderers非常昂贵,因此请始终尽量保持它们的轻量级。

package 
{
    import flash.events.MouseEvent; 
    import mx.core.IDataRenderer;   
    import spark.components.supportClasses.ButtonBase;
    import spark.components.supportClasses.SkinnableComponent;

    [SkinState("normal")]
    [SkinState("hovered")]
    public class LearningRenderer extends SkinnableComponent implements IDataRenderer
    {

        /** Define the skin parts. */
        [SkinPart(required="true")]
        public var deleteButton:ButtonBase;

        public function LearningRenderer()
        {
            super();
            // Set the skin class.
            setStyle("skinClass", LearningRendererSkin);
            // Add event listeners to support HOVERED.
            addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
            addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
        }       

        /** Implement the partAdded() method. */
        override protected function partAdded(partName:String, instance:Object):void 
        {
            super.partAdded(partName, instance);
            if(instance == deleteButton){
                instance.addEventListener(MouseEvent.CLICK, button_clickHandler);
            }
        }

        /** Implement the partRemoved() method. */
        override protected function partRemoved(partName:String, instance:Object):void
        {
            if(instance == deleteButton){
                instance.removeEventListener(MouseEvent.CLICK, button_clickHandler);
            }
        }

        /** Implement the getCurrentSkinState() method. */
        override protected function getCurrentSkinState():String 
        {   
            var returnState:String = "normal";
            if (bRollOver)
                returnState = "hovered";
            return returnState;
        }

        public function get data():Object
        {
            return _data;
        }

        public function set data(value:Object):void
        {
            _data = value;
        }

        /** Add methods, properties, and metadata. */
        private var _data:Object;
        private var bRollOver:Boolean = false;

        /**
         * Handlers
         */         
        protected function button_clickHandler(eventObj:MouseEvent):void {
            //Handle click
        }

        protected function rollOverHandler(eventObj:MouseEvent):void{
            bRollOver = true;
            invalidateSkinState();
        }

        protected function rollOutHandler(eventObj:MouseEvent):void{
            bRollOver = false;
            invalidateSkinState();
        }       

    }
}

这是具有所需deleteButton的皮肤:

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx">
    <!-- host component -->
    <fx:Metadata>
        [HostComponent("LearningRenderer")]
    </fx:Metadata>
    <!-- states -->
    <s:states>
        <s:State name="normal" />
        <s:State name="hovered" />
    </s:states>
    <s:Button id="deleteButton" label="Delete"/>        
</s:Skin>

答案 1 :(得分:0)

首先 - 确保您使用的是Spark列表控件,而不是MX控件。众所周知,MX项目渲染器很难处理。相比之下,火花渲染表现相当好,易于处理。

现在......从这里开始Flex Quick Start - Using Spark Item Renderers

最后 - 这里是关于如何Define a custom Spark Item Render的更深入的讨论。


我知道你说“我在ActionScript 3中制作了所有这些”(我认为这意味着你出于某种原因避免使用mxml)。 ...但是如果您正在使用列表控件和项呈示器,那么即使您没有使用MXML进行编码,也可以使用Flex框架。

因此,上述资源是适用的,无论是MXML还是纯AS3。请记住,每个MXML文档都对应于由mxml编译器生成的AS3类。 mxml文档的根xml标记告诉您生成的类将扩展到什么类。

因此,当您看到名为“MyRenderer.mxml”的mxml文件时,其内容如下所示:

<s:ItemRenderer>
   ...
</s:ItemRenderer>

你知道这对应于纯AS3类定义,如下所示:

class MyRenderer extends ItemRenderer {
    ...
}

在我看来 - 当你开始使用ItemRenderers并使用Spark(甚至是MX)组件时,MXML比纯粹的AS3更容易使用 。毕竟,框架组件是设计的,可以从mxml中使用。

祝你好运!

答案 2 :(得分:0)

我发现最简单的解决方案是使用数据网格和最后一列的项呈示器。我扩展了高级数据网格以生成“EditabledList”类,并修改了“公共函数集列”方法以自动将我的删除按钮列添加到结尾。然后我为该列创建了一个删除按钮项呈示器。绑定点击操作有点棘手,因为我只引用了该行的数据,而不是对列表的引用。我通过覆盖“public set dataProvider”方法来解决这个问题,用我自己的自定义对象替换列表中的每个项目,该对象具有对列表的引用,唯一ID和“removeMe”方法。我将此对象称为EditableListItem。不幸的副作用是数据绑定必须以额外的“.data”作为前缀,因为用户的对象存储在我的EditableListItem的“data”属性中。

这就是我的渲染器的样子。

<fx:Component className="buttonRenderer">
    <s:MXAdvancedDataGridItemRenderer height="100%" width="100%">
        <s:Button left="5" top="5" skinClass="{buttonSkin}" click="EditableList.clickButton(data)"
            useHandCursor="true" buttonMode="true" toolTip="Remove item"/>
    </s:MXAdvancedDataGridItemRenderer>
</fx:Component>

buttonSkin刚刚渲染了具有翻转效果的自定义图像。