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 ответа
Я в основном отвечу на ваш второстепенный вопрос (предполагаю, что он решит основную проблему одним махом): поскольку анти-паттерны идут, это неплохой пример;)
- Вы вручную загружаете изображения, пока
Image
класс имеет встроенную загрузку; просто дать ссылку на егоsource
свойство, и оно автоматически загрузит его. - Вы устанавливаете
Image
экземпляр как источник другогоImage
пример;source
свойство ожидает URL или ByteArrays; Я удивлен, что это не выдает ошибку; класс Image, вероятно, достаточно умен, чтобы извлечьsource
другого экземпляра изображения. Timer
избыточно Как сказано,Image
автоматически заботится о загрузке своего контента.s:Image
тег не обернут вItemRenderer
и, следовательно, не должны иметь доступа кdata
свойство: этот код даже не должен компилироваться- Нет смысла иметь
Bindable
имущество_pics
если вы не планируете связывать это. - Вы используете 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 );
}
}
}