1

下面的代码在使用自定义单元格渲染器(CustomListCell 类)的主控制器类中设置了一个 List 对象。CustomListCell 类为单元格创建一个 Button 对象,该对象将用于从 List 的 DataProvider 中删除自身。

如何从其自定义单元格渲染器正确访问父 List 对象?

//Controller Class
private function createList():void
 {
 provider = new DataProvider(data);

 list = new List();
 list.width = 200;
 list.height = 400;
 list.rowHeight = 50;
 list.dataProvider = provider;
 list.setStyle("cellRenderer", CustomListCell);
 }

-----

//CustomListCell Class
import fl.controls.Button;

public class CustomListCell extends Sprite implements ICellRenderer
 {     
 public function CustomListCell()
  {
  var button:Button = new Button();
  button.label = "Delete Cell";
  button.addEventListener(MouseEvent_MOUSE_DOWN, deleteCellHandler);
        addChild(button);
  }

 private function deleteCellHandler(evt:MouseEvent):void
  {
  //Access List/DataProvider Here
  }

 //required implemented ICellRenderer functions follow
 }

更新

以下是我使用 Flash v3 List 组件实现 ICellRenderer 的工作自定义渲染器。List 的 dataProvider 由每个单元格的 2 个元素组成:randomColor 和 randomNumber。

package
{
//Imports
import fl.controls.Button;
import fl.controls.List;
import fl.controls.listClasses.ICellRenderer; 
import fl.controls.listClasses.ListData;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.geom.ColorTransform;

//Class
public class TouchListRenderer extends Sprite implements ICellRenderer
    {
    //Properties
    private var cellWidthProperty:Number;
    private var cellHeightProperty:Number;
    private var dataProperty:Object;
    private var listDataProperty:ListData;  
    private var selectedProperty:Boolean;

    //Cell Display Objects
    private var backgroundCanvas:MySprite = new MySprite();
    private var numberTextField:TextField = new TextField();
    private var button:Button = new Button();

    //Constructor
    public function TouchListRenderer()
        {
        }

    //Size Setter (Getter Functions Intentionally Omitted)
    public function setSize(width:Number, height:Number):void
        {
        cellWidthProperty = width;
        cellHeightProperty = height;
        }

    //Data Setter
    public function set data(value:Object):void
        {
        dataProperty = value;
        }

    //Data Getter
    public function get data():Object
        { 
        return dataProperty; 
        }

    //List Data Setter
    public function set listData(value:ListData):void
        { 
        listDataProperty = value;
        }

    //List Data Getter
    public function get listData():ListData
        { 
        return listDataProperty; 
        }

    //Selected Setter
    public function set selected(value:Boolean):void
        { 
        selectedProperty = value;

        layout();
        }

    //Selected Getter
    public function get selected():Boolean
        { 
        return selectedProperty;
        }

    //Size And Layout
    private function layout():void
        {
        var newColor:ColorTransform = new ColorTransform();
        newColor.color = dataProperty.randomColor;

        backgroundCanvas.transform.colorTransform = newColor;
        backgroundCanvas.scaleX = cellWidthProperty / backgroundCanvas.width;
        backgroundCanvas.scaleY = cellHeightProperty / backgroundCanvas.height;

        numberTextField.text = dataProperty.randomNumber;
        numberTextField.autoSize = TextFieldAutoSize.LEFT;
        numberTextField.textColor = 0xFFFFFF;
        numberTextField.x = 50;
        numberTextField.y = cellHeightProperty / 2 - numberTextField.height / 2;
        numberTextField.border = true;
        numberTextField.selectable = false;

        button.label = "Delete";
        button.x = cellWidthProperty - button.width - 50;
        button.y = cellHeightProperty / 2 - button.height / 2;
        button.drawNow();
        button.addEventListener(MouseEvent.MOUSE_DOWN, buttonClickEventHandler);

        addChild(backgroundCanvas);
        addChild(numberTextField);
        addChild(button);
        }

    //Button Click Event Handler
    private function buttonClickEventHandler(evt:MouseEvent):void
        {
        List(listDataProperty.owner).removeItemAt(listDataProperty.index);
        }

    //Style Setter
    public function setStyle(style:String, value:Object):void
        {
        }

    //Mouse State Setter
    public function setMouseState(state:String):void
        {
        }
    } 
} 

package
{
import flash.display.Sprite;

public class MySprite extends Sprite
    {
    public function MySprite()
        {
        graphics.beginFill(0xFF0000);
        graphics.drawRect(0, 0, 10, 10);
        graphics.endFill();
        }
    }
}
4

2 回答 2

2

啊!答案一直摆在我面前!下次提醒我检查文档:

List(listData.owner)

fl.controls.listClasses.ListData.owner

于 2010-12-24T11:18:47.203 回答
1

有多种方法可以做到这一点。

这是一个非常hacky的解决方案:使用一个图标,并让该图标调度一个关闭事件。

这个想法是您将在每个列表单元格中放置一个自定义影片剪辑作为图标。该图标将发送一个带有单击的单元格索引的事件,以便您可以将其删除。

第一步:制作一个基本的自定义事件来传递单元格索引:

package{

    import flash.events.Event;

    public class CloseEvent extends Event{

        public static const CLOSE:String = 'close';
        public var index:int;

        public function CloseEvent(type:String,bubbles:Boolean = true,cancelable:Boolean=true){
            super(type,bubbles,cancelable);
        }

    }

}

第二步::画一个关闭图标什么的,把它转换成MovieClip和Export for Actionscript

第三步:添加事件侦听器以在单击关闭图标时调度自定义事件。

在关闭图标 Movie Clip 中,我放置了以下操作:

import fl.controls.listClasses.CellRenderer;

//setup click
buttonMode = true;
if(parent) parent.mouseChildren = true;
addEventListener(MouseEvent.MOUSE_DOWN,dispatchClose);
//setup event
var closeEvent:CloseEvent = new CloseEvent(CloseEvent.CLOSE,true);
if(parent) closeEvent.index = CellRenderer(parent).listData.index;
//listen to click and pass on
function dispatchClose(event:MouseEvent):void {
    dispatchEvent(closeEvent);
}

非常基本的东西,听鼠标按下,创建一个事件并设置索引并在点击时调度该事件。该图标被添加到单元格渲染器中,因此单元格渲染器是它的父级,它具有listData属性,其中包含单元格的索引。

下面是测试片段的样子:

import fl.data.DataProvider;

var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1),icon:Close});
ls.dataProvider = dp;

addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
    ls.removeItemAt(event.index);
}

由于 CloseEvent 冒泡,我们可以从单元格渲染器图标之外捕获它,并告诉列表删除该索引处的项目。可以在图标中做到这一点,但有必要“爬上”层次结构一直到列表,而且它已经很老套了。

我这样做是因为,我可能像 @TheDarkIn1978 :P 一样懒惰来实现 ICellRenderer 函数。然后我再次查看问题代码,不明白为什么自定义单元格扩展了 Sprite,而 CellRenderer 已经实现了 ICellRenderer 函数。

所以这是我尝试以一种不那么老套的方式来做这件事:

package{

    import fl.controls.*;
    import fl.controls.listClasses.*;
    import fl.data.*;
    import flash.events.*;

    public class SCListCell extends CellRenderer implements ICellRenderer{

        protected var closeButton:Button;
        protected var closeEvent:CloseEvent;

        override protected function configUI():void {
            super.configUI();
            closeButton = new Button();
            closeButton.label = 'x';
            closeButton.buttonMode = true;
            closeButton.setSize(30,20);
            closeButton.drawNow();
            closeButton.addEventListener(MouseEvent.CLICK,close);
            addChild(closeButton);
            closeEvent = new CloseEvent(CloseEvent.CLOSE);
        }

        private function close(event:MouseEvent):void{
            closeEvent.index = listData.index;
            dispatchEvent(closeEvent);
        }

        override protected function drawLayout():void{
            mouseChildren = true;
            closeButton.x = width-closeButton.width;
        }

    }

}

使用相同的 CloseEvent 传递索引,并且自定义单元格可以直接访问listData对象以获取索引,因此示例片段如下所示:

import fl.data.DataProvider;

var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;

addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
    ls.removeItemAt(event.index);
}

ls.setStyle('cellRenderer',SCListCell);

所以回答你的问题

如何从其自定义单元格渲染器正确访问父 List 对象?

您可以使用单元格渲染器的 listData 属性。如果你愿意,你可以,但这意味着要上升几个级别:

package{

    import fl.controls.*;
    import fl.controls.listClasses.*;
    import fl.data.*;
    import flash.events.*;

    public class SCListCell extends CellRenderer implements ICellRenderer{

        protected var closeButton:Button;

        override protected function configUI():void {
            super.configUI();
            closeButton = new Button();
            closeButton.label = 'x';
            closeButton.buttonMode = true;
            closeButton.setSize(30,20);
            closeButton.drawNow();
            closeButton.addEventListener(MouseEvent.CLICK,close);
            addChild(closeButton);
        }

        private function close(event:MouseEvent):void{
            List(this.parent.parent.parent).removeItemAt(listData.index);
        }

        override protected function drawLayout():void{
            mouseChildren = true;
        closeButton.x = width-closeButton.width;
        }

    }

}

这使得列表创建部分非常简单:

import fl.data.DataProvider;

var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;

ls.setStyle('cellRenderer',SCListCell);

在这种情况下不需要 CloseEvent。

高温高压

于 2010-12-15T00:48:40.580 回答