Flex:为什么TileList图像会在拖动时消失?

时间:2012-05-11 22:01:36

标签: actionscript-3 flex drag-and-drop tilelist

我正在开发一个Flex Air(桌面)应用程序,它将来自本地文件系统的图像加载到TileList中。然后,用户可以将这些图像从列表中拖出(复制)到另一个控件上。

我终于正确显示了图像(并且在滚动TileList后没有消失)但是它们似乎在拖动操作开始时从TileList中消失。

我来自.NET背景,我只是在学习AS3 / Flex,所以如果你看到我在这里使用任何反模式,请随意指出它们!

示例代码如下(我试图尽量减少它)。


Test.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx">
    <fx:Script>
        <![CDATA[

            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;

            [Bindable]
            protected var _pics:ArrayCollection = new ArrayCollection();

            protected function picsList_creationCompleteHandler(event:FlexEvent):void
            {
                const imageFolderPath:String = "c:\\users\\bbrooks\\Pictures";

                var imageDir:File = new File(imageFolderPath);
                var imageFiles:Array = imageDir.getDirectoryListing();
                for each(var imageFile:File in imageFiles)
                {
                    _pics.addItem(new PictureObject(imageFile.nativePath));
                }

                // give images a chance to load
                var timer:Timer = new Timer(1000);
                timer.addEventListener(TimerEvent.TIMER, onTimerExpired);
                timer.start();
            }

            protected function onTimerExpired(event:TimerEvent):void
            {
                picsList.dataProvider = _pics;
            }

        ]]>
    </fx:Script>

    <mx:TileList id="picsList" x="0" y="0" width="100%" height="100%" dragEnabled="true" dragMoveEnabled="false"
                 creationComplete="picsList_creationCompleteHandler(event)" >
        <mx:itemRenderer>
            <fx:Component>
                <mx:Image width="75" height="75" source="{data.image}" />
            </fx:Component>
        </mx:itemRenderer>
    </mx:TileList>

</s:WindowedApplication>


PictureObject.as:

package
{
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.events.Event;
    import flash.net.URLRequest;

    import mx.controls.Image;

    [Bindable]
    [RemoteClass]
    public class PictureObject extends Object
    {
        protected var _image:Image = null;
        public function get image():Image { return _image; }
        public function set image(newValue:Image):void { _image = newValue; }

        public function PictureObject(path:String)
        {
            var imageLoader:Loader = new Loader();
            imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
            imageLoader.load(new URLRequest(path));
        }

        protected function onImageLoaded(e:Event):void
        {
            var imageLoader:Loader = LoaderInfo(e.target).loader;
            var bmp:Bitmap = Bitmap(imageLoader.content);

            _image = new Image();           
            _image.smoothBitmapContent = true;
            _image.source = new Bitmap(bmp.bitmapData);
            _image.width = imageLoader.width;
            _image.height = imageLoader.height;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我将主要回复你的第二个问题(猜测它将一举解决主要问题):反模式去了,这不是一个坏的例子;)

  1. Image类内置加载时,您手动加载图像;只需为其source属性提供一个URL,它就会自动加载它。
  2. 您正在设置Image个实例作为另一个Image实例的来源; source属性需要URL或ByteArrays;我很惊讶它没有抛出错误; Image类可能足够智能,可以提取另一个Image实例的source
  3. Timer是多余的。如上所述,Image会自动负责加载其内容。
  4. s:Image标记未包含在ItemRenderer中,因此无法访问data属性:此代码甚至不应编译。
  5. 如果您不打算绑定它,那么拥有Bindable属性_pics是没有意义的。
  6. 您使用mx TileList。为什么不使用更“现代”的Spark版本? (这并不意味着mx类在Spark应用程序中不起作用)。
  7. 所以你有很多要删除的事情。你可以完全废弃PictureObject类;删除定时器代码;只需将URL字符串添加到_pics集合中。作为一个加号你也可以用带有TileLayout的Spark List替换mx TileList;像这样的东西:

    <s:List id="picsList">
        <s:layout>
            <s:TileLayout />
        </s:layout>
        <s:itemRenderer>
            <fx:Component>
                <s:ItemRenderer>
                    <s:Image source="{data}" />
                </s:ItemRenderer>
            </fx:Component>
        </s:itemRenderer>
    </s:List>
    

    ActionScript部分可以简化为:

    const imageFolderPath:String = "c:\\users\\bbrooks\\Pictures";
    
    var imageDir:File = new File(imageFolderPath);
    var imageFiles:Array = imageDir.getDirectoryListing();
    picsList.dataProvider = new ArrayCollection(imageFiles);
    

答案 1 :(得分:0)

感谢RIAstar。你的回答让我走上了解决问题的轨道。新的示例代码如下所示。

最初的问题似乎与mx:Image控件有关。不知道为什么,但使用s:图像控件似乎有效。

当然,只需将数据源设置为文件路径列表就可以在没有PictureObject类的情况下完成,但我稍后使用了图像数据,我希望通过提供图像数据来使其工作自定义渲染器动态。

<强> Test.mxml:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/mx">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;

            import spark.components.Image;

            protected var _pics:ArrayCollection = new ArrayCollection();

            protected function picsList_creationCompleteHandler(event:FlexEvent):void
            {
                const imageFolderPath:String = "c:\\users\\bbbrooks\\Pictures";

                var imageDir:File = new File(imageFolderPath);
                var imageFiles:Array = imageDir.getDirectoryListing();
                for each(var imageFile:File in imageFiles)
                {
                    if (imageFile.extension == "jpg")
                    {
                        _pics.addItem(new PictureObject(imageFile.nativePath));
                    }
                }

                // give images a chance to load
                var timer:Timer = new Timer(1000);
                timer.addEventListener(TimerEvent.TIMER, onTimerExpired);
                timer.start();
            }

            protected function onTimerExpired(event:TimerEvent):void
            {
                picsList.dataProvider = _pics;
            }

        ]]>
    </fx:Script>

    <s:List id="picsList" x="0" y="0" width="100%" height="100%" 
            creationComplete="picsList_creationCompleteHandler(event)"
            dragEnabled="true" dragMoveEnabled="false">
        <s:layout>
            <s:TileLayout />
        </s:layout>
        <s:itemRenderer>
            <fx:Component>
                <s:ItemRenderer>
                    <s:Image id="imageDisplay" 
                             width="75" height="75" source="{data.bmp}" /> 
                </s:ItemRenderer>
            </fx:Component>
        </s:itemRenderer>
    </s:List>

</s:WindowedApplication>


PictureObject.as

package
{
    import flash.display.Bitmap;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.events.Event;
    import flash.net.URLRequest;

    import mx.controls.Image;

    [RemoteClass]
    [Bindable]
    public class PictureObject extends Object
    {
        protected var _bmp:Bitmap = null;
        public function get bmp():Bitmap { return _bmp; }
        public function set bmp(newValue:Bitmap):void { _bmp = newValue; }

        public function PictureObject(path:String)
        {
            var imageLoader:Loader = new Loader();
            imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
            imageLoader.load(new URLRequest(path));
        }

        protected function onImageLoaded(e:Event):void
        {
            var imageLoader:Loader = LoaderInfo(e.target).loader;

            // create our own copy of the bits in the Loader
            var bmp:Bitmap = Bitmap(imageLoader.content);
            _bmp = new Bitmap( Bitmap(imageLoader.content).bitmapData );
        }
    }
}