Flex: почему изображения 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 ответа

Решение

Я в основном отвечу на ваш второстепенный вопрос (предполагаю, что он решит основную проблему одним махом): поскольку анти-паттерны идут, это неплохой пример;)

  1. Вы вручную загружаете изображения, пока Image класс имеет встроенную загрузку; просто дать ссылку на его source свойство, и оно автоматически загрузит его.
  2. Вы устанавливаете Image экземпляр как источник другого Image пример; source свойство ожидает URL или ByteArrays; Я удивлен, что это не выдает ошибку; класс Image, вероятно, достаточно умен, чтобы извлечь source другого экземпляра изображения.
  3. Timer избыточно Как сказано, Image автоматически заботится о загрузке своего контента.
  4. s:Image тег не обернут в ItemRenderer и, следовательно, не должны иметь доступа к data свойство: этот код даже не должен компилироваться
  5. Нет смысла иметь Bindable имущество _pics если вы не планируете связывать это.
  6. Вы используете mx TileList. Почему бы не использовать более "современную" версию Spark? (Это не означает, что класс mx не будет работать в приложении Spark).

Таким образом, у вас есть много дел для удаления. Вы можете полностью удалить класс PictureObject; удалить код таймера; и просто добавьте строки URL в _pics коллекция. В качестве плюса вы также можете заменить mx TileList списком искр на TileLayout; что-то вроде этого:

<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);

Спасибо РИАстар. Ваш ответ поставил меня на путь решения проблемы. Новый образец кода появится ниже.

Первоначальная проблема, кажется, была с mx:Image control. Не уверен, почему, но кажется, что работает управление s:Image.

Конечно, это может быть достигнуто без использования класса 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 );
        }
    }
}
Другие вопросы по тегам