下面是我们尝试在同一个基于列表的控件中拖放列表项。我们试图镜像与#34相同的功能;在同一控件中拖放#34;使用flex组件:http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7cfd.html。
当用户重新排序列表时,每个索引都将写入一个文件,以便重新排序的列表将保持原样刷新屏幕。
虽然我们可以渲染化身并将拖动的对象推到基于列表的控件的末尾,但我们无法将对象拖动到基于列表的控件中的特定索引。
我们能做什么:谷歌 - > msn - >雅虎 - >谷歌
我们无法做到的事:google - > msn - >谷歌 - >雅虎
最后,任何关于如何为屏幕刷新存储重新排序列表的想法都将受到赞赏。
构建我们接受了扩展列表的建议以及其他人的建议:mironcaius和Josh Tynjala:http://forum.starling-framework.org/topic/defaultlistitemrenderer-does-not-update-lables和http://wiki.starling-framework.org/feathers/drag-drop(请参阅将显示对象本身添加为拖动数据)。
Main.as
package feathers.examples.dragDrop
{
import feathers.data.ListCollection;
import feathers.dragDrop.IDragSource;
import feathers.dragDrop.IDropTarget;
import feathers.themes.AeonDesktopTheme;
import starling.display.Sprite;
import starling.events.Event;
public class Main extends Sprite implements IDragSource, IDropTarget
{
public static var listCollection:ListCollection = new ListCollection([{playerName:"yahoo"},{playerName:"msn"},{playerName:"google"}]);
public function Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event:Event):void
{
new AeonDesktopTheme();
var listTeam1:DragDropList = new DragDropList();
listTeam1.dataProvider = listCollection;
listTeam1.itemRendererProperties.labelField = "playerName";
listTeam1.itemRendererProperties.height = 38;
this.addChild(listTeam1);
//listTeam1.hasElasticEdges = false;
//listTeam1.addEventListener("changeTeam", changeTeamHandler);
}
/*private function changeTeamHandler(event:Event):void
{
//trace(event.target.data);
}*/
}
}
DragDropList.as
package feathers.examples.dragDrop
{
import feathers.controls.Label;
import feathers.controls.List;
import feathers.core.FeathersControl;
import feathers.dragDrop.DragData;
import feathers.dragDrop.DragDropManager;
import feathers.dragDrop.IDragSource;
import feathers.dragDrop.IDropTarget;
import feathers.events.DragDropEvent;
import starling.display.Quad;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
//[Event(name="changeTeam", type="Event")]
public class DragDropList extends List implements IDropTarget, IDragSource
{
public function DragDropList()
{
super();
addEventListener(TouchEvent.TOUCH, touchHandler);
addEventListener(DragDropEvent.DRAG_ENTER, dragEnterHandler);
addEventListener(DragDropEvent.DRAG_DROP, dragDropHandler);
addEventListener(DragDropEvent.DRAG_COMPLETE, dragCompleteHandler);
}
protected function touchHandler(event:TouchEvent):void
{
var touch:Touch = event.touches[0];
if(touch.phase == TouchPhase.BEGAN)
{
if(selectedItem)
{
var fc:FeathersControl = new FeathersControl();
fc.addChild(new Quad(150, 50, 0xFFFFFF));
var lbl:Label = new Label();
lbl.text = selectedItem["playerName"];
fc.addChild(lbl);
var dd:DragData = new DragData();
dd.setDataForFormat("playerFormat", selectedItem);
DragDropManager.startDrag(this, touch, dd, fc);
}
}
}
protected function dragEnterHandler(event:DragDropEvent, dragData:DragData):void
{
if(dragData.hasDataForFormat("playerFormat"))
{
DragDropManager.acceptDrag(this);
}
}
protected function dragDropHandler(event:DragDropEvent, dragData:DragData):void
{
if(dragData.hasDataForFormat("playerFormat"))
{
var obj:Object = dragData.getDataForFormat("playerFormat");
Main.listCollection.push(obj);
//dispatchEventWith("changeTeam", false, obj);
}
}
protected function dragCompleteHandler(event:DragDropEvent):void
{
if(event.isDropped)
{
Main.listCollection.removeItem(selectedItem);
}
}
}
}
答案 0 :(得分:2)
我现在已经合理地实现了拖动可排序的羽毛列表工作。我确信它可以改进,作为一个AS3 / Starling / Feathers新手,我确定我会以一种不太理想的方式完成某些部分,但我很漂亮很高兴它是如何运作的。
通过检测拖动是否接近列表的顶部/底部,touchHandler
,启动较慢的滚动,或超过列表的顶部/底部来控制滚动,从而启动更快的滚动。
希望它对您有用,并随时回答任何问题或提出改进建议!
泰德
此外,如果他们感兴趣,这些是我在代码中使用的两个拖动图像:
<强> Main.as 强>
package feathers.examples.dragDrop
{
import feathers.controls.Button;
import feathers.controls.List;
import feathers.data.ListCollection;
import feathers.dragDrop.IDragSource;
import feathers.dragDrop.IDropTarget;
import feathers.themes.MetalWorksMobileTheme;
import starling.core.Starling;
import starling.display.Sprite;
import starling.events.Event;
public class Main extends Sprite implements IDragSource, IDropTarget
{
private var list:List;
public function Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event:Event):void
{
new MetalWorksMobileTheme();
const PADDING:int = 100;
list = new List();
list.width = Starling.current.viewPort.width - (PADDING * 2);
list.height = Starling.current.viewPort.height - (PADDING * 2);
this.addChild( list );
list.y = PADDING;
list.x = PADDING;
list.itemRendererType = DragDropItemRenderer;
resetDefaultListData();
var resetButton:Button = new Button();
resetButton.label = "Reset List Data";
resetButton.addEventListener(Event.TRIGGERED, resetButtonHandler);
resetButton.nameList.add(Button.ALTERNATE_NAME_QUIET_BUTTON);
this.addChild(resetButton);
resetButton.validate();
resetButton.x = (Starling.current.viewPort.width / 2) - (resetButton.width / 2);
resetButton.y = Starling.current.viewPort.height - resetButton.height - (PADDING / 5);
}
private function resetButtonHandler(e:Event):void
{
resetDefaultListData();
}
private function resetDefaultListData():void
{
var defaultData:ListCollection = new ListCollection(
[
{text: 'Test Item 1' },
{text: 'Test Item 2' },
{text: 'Test Item 3' },
{text: 'Test Item 4' },
{text: 'Test Item 5' },
{text: 'Test Item 6' },
{text: 'Test Item 7' },
{text: 'Test Item 8' },
{text: 'Test Item 9' },
{text: 'Test Item 10' },
{text: 'Test Item 11' },
{text: 'Test Item 12' },
{text: 'Test Item 13' },
{text: 'Test Item 14' },
{text: 'Test Item 15' },
{text: 'Test Item 16' },
{text: 'Test Item 17' },
{text: 'Test Item 18' },
{text: 'Test Item 19' },
{text: 'Test Item 20' },
{text: 'Test Item 21' },
{text: 'Test Item 22' },
{text: 'Test Item 23' },
{text: 'Test Item 24' },
{text: 'Test Item 25' },
{text: 'Test Item 26' },
{text: 'Test Item 27' },
{text: 'Test Item 28' },
{text: 'Test Item 29' },
{text: 'Test Item 30' },
{text: 'Test Item 31' },
{text: 'Test Item 32' },
{text: 'Test Item 33' },
{text: 'Test Item 34' },
{text: 'Test Item 35' },
{text: 'Test Item 36' },
{text: 'Test Item 37' },
{text: 'Test Item 38' },
{text: 'Test Item 39' },
{text: 'Test Item 40' },
{text: 'Test Item 41' },
{text: 'Test Item 42' },
{text: 'Test Item 43' },
{text: 'Test Item 44' },
{text: 'Test Item 45' },
{text: 'Test Item 46' },
{text: 'Test Item 47' },
{text: 'Test Item 48' },
{text: 'Test Item 49' },
{text: 'Test Item 50' },
{text: 'Test Item 51' },
{text: 'Test Item 52' },
{text: 'Test Item 53' },
{text: 'Test Item 54' },
{text: 'Test Item 55' },
{text: 'Test Item 56' },
{text: 'Test Item 57' },
{text: 'Test Item 58' },
{text: 'Test Item 59' },
{text: 'Test Item 60' },
{text: 'Test Item 61' },
{text: 'Test Item 62' },
{text: 'Test Item 63' },
{text: 'Test Item 64' },
{text: 'Test Item 65' },
{text: 'Test Item 66' },
{text: 'Test Item 67' },
{text: 'Test Item 68' },
{text: 'Test Item 69' },
{text: 'Test Item 70' },
{text: 'Test Item 71' },
{text: 'Test Item 72' },
{text: 'Test Item 73' },
{text: 'Test Item 74' },
{text: 'Test Item 75' },
{text: 'Test Item 76' },
{text: 'Test Item 77' },
{text: 'Test Item 78' },
{text: 'Test Item 79' },
{text: 'Test Item 80' },
{text: 'Test Item 81' },
{text: 'Test Item 82' },
{text: 'Test Item 83' },
{text: 'Test Item 84' },
{text: 'Test Item 85' },
{text: 'Test Item 86' },
{text: 'Test Item 87' },
{text: 'Test Item 88' },
{text: 'Test Item 89' },
{text: 'Test Item 90' },
{text: 'Test Item 91' },
{text: 'Test Item 92' },
{text: 'Test Item 93' },
{text: 'Test Item 94' },
{text: 'Test Item 95' },
{text: 'Test Item 96' },
{text: 'Test Item 97' },
{text: 'Test Item 98' },
{text: 'Test Item 99' },
{text: 'Test Item 100' },
]);
list.dataProvider = defaultData;
}
}
}
<强> DragDropItemRenderer.as 强>
package feathers.examples.dragDrop
{
import flash.events.TimerEvent;
import flash.utils.Timer;
import feathers.controls.Label;
import feathers.controls.List;
import feathers.controls.renderers.IListItemRenderer;
import feathers.core.FeathersControl;
import feathers.dragDrop.DragData;
import feathers.dragDrop.DragDropManager;
import feathers.dragDrop.IDragSource;
import feathers.dragDrop.IDropTarget;
import feathers.events.DragDropEvent;
import starling.display.Button;
import starling.display.DisplayObject;
import starling.display.Quad;
import starling.display.Sprite;
import starling.events.Event;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
import starling.textures.Texture;
import starling.utils.Color;
public class DragDropItemRenderer extends FeathersControl implements IListItemRenderer, IDragSource, IDropTarget
{
[Embed(source="drag-handle.png")]
public static const DragHandle:Class;
[Embed(source="drag-handle-down.png")]
public static const DragHandleDown:Class;
private const LIST_ITEM_DRAG:String = "LIST_ITEM_DRAG";
public function DragDropItemRenderer()
{
//drag
this.addEventListener(DragDropEvent.DRAG_START, dragStartHandler);
this.addEventListener(DragDropEvent.DRAG_COMPLETE, dragCompleteHandler);
//drop
this.addEventListener(DragDropEvent.DRAG_ENTER, dragEnterHandler);
this.addEventListener(DragDropEvent.DRAG_EXIT, dragExitHandler);
this.addEventListener(DragDropEvent.DRAG_MOVE, dragMoveHandler);
this.addEventListener(DragDropEvent.DRAG_DROP, dragDropHandler);
}
//================================================================================================
//drag interface
//================================================================================================
private function dragStartHandler(event:DragDropEvent, dragData:DragData):void
{
//the drag was started with the call to DragDropManager.startDrag()
}
private function dragCompleteHandler(event:DragDropEvent, dragData:DragData):void
{
if(event.isDropped)
{
//the object successfully dropped at a valid location
}
stopScrolling();
}
private var carryOnScrolling:Boolean=false;
private var scrollDirection:String="";
private var scrollSpeed:String="";
private var scrollTimer:Timer;
private var avatarContainer:Sprite;
private var avatarBg:Quad;
private var avatarLabel:Label;
private const LIST_SCROLL_DETECT_HEIGHT:int = 30;
private const SCROLL_SIZE:int = 25;
private const SCROLL_SPEED_SLOW:String = "SLOW";
private const SCROLL_SPEED_FAST:String = "FAST";
private const SCROLL_DIRECTION_UP:String = "UP";
private const SCROLL_DIRECTION_DOWN:String = "DOWN";
private const SCROLL_TIME_MS_SLOW:int = 75;
private const SCROLL_TIME_MS_FAST:int = 25;
private var scrollSpeedMSToUse:int;
private function startScrollingList(direction:String, speed:String):void
{
scrollDirection = direction;
scrollSpeed = speed;
carryOnScrolling = true;
doScrollWorker();
if(scrollTimer != null)
{
scrollTimer.stop();
scrollTimer = null;
}
if(scrollSpeed == SCROLL_SPEED_FAST)
scrollSpeedMSToUse = SCROLL_TIME_MS_FAST;
else
scrollSpeedMSToUse = SCROLL_TIME_MS_SLOW;
scrollTimer = new Timer(scrollSpeedMSToUse);
scrollTimer.addEventListener(TimerEvent.TIMER, onScrollTimerHandler);
scrollTimer.start();
}
private function stopScrolling():void
{
carryOnScrolling = false;
}
private function onScrollTimerHandler(e:TimerEvent):void
{
if(carryOnScrolling)
{
doScrollWorker();
}
else
{
scrollTimer.stop();
scrollTimer = null;
}
}
private function doScrollWorker():void
{
const EXTRA_SCROLL_PADDING:int = 20;
var scrollSizeToUse:int = SCROLL_SIZE;
if(scrollDirection == SCROLL_DIRECTION_UP)
{
if((this.owner.verticalScrollPosition + scrollSizeToUse) < (this.owner.maxVerticalScrollPosition + EXTRA_SCROLL_PADDING))
{
this.owner.scrollToPosition(this.owner.horizontalScrollPosition, this.owner.verticalScrollPosition + scrollSizeToUse, (scrollSpeedMSToUse / 1000));
}
}
else
{
if((this.owner.verticalScrollPosition - scrollSizeToUse) > (this.owner.minVerticalScrollPosition - EXTRA_SCROLL_PADDING))
{
this.owner.scrollToPosition(this.owner.horizontalScrollPosition, this.owner.verticalScrollPosition - scrollSizeToUse, (scrollSpeedMSToUse / 1000));
}
}
}
private function touchHandler(event:TouchEvent):void
{
if(DragDropManager.isDragging)
{
//check if the drag is close enough to the top / bottom to start scrolling
var touchScrollTest:Touch = event.getTouch(this);
if(touchScrollTest)
{
if(touchScrollTest.globalY < this.owner.y)
{
startScrollingList(SCROLL_DIRECTION_DOWN, SCROLL_SPEED_FAST);
}
else if(touchScrollTest.globalY < this.owner.y + LIST_SCROLL_DETECT_HEIGHT)
{
startScrollingList(SCROLL_DIRECTION_DOWN, SCROLL_SPEED_SLOW);
}
else if(touchScrollTest.globalY > this.owner.y + this.owner.height)
{
startScrollingList(SCROLL_DIRECTION_UP, SCROLL_SPEED_FAST);
}
else if(touchScrollTest.globalY > this.owner.y + this.owner.height - LIST_SCROLL_DETECT_HEIGHT)
{
startScrollingList(SCROLL_DIRECTION_UP, SCROLL_SPEED_SLOW);
}
else
{
stopScrolling();
}
}
//one drag at a time, please
return;
}
if(this._touchID >= 0)
{
var touch:Touch = event.getTouch(this._draggedObject, null, this._touchID);
if(touch.phase == TouchPhase.MOVED)
{
this._touchID = -1;
avatarContainer = new Sprite();
const AVATAR_X_OFFSET:int = 75;
avatarBg = new Quad(this.width - AVATAR_X_OFFSET, this.height, starling.utils.Color.LIME);
avatarBg.alpha = 0.25;
avatarLabel = new Label();
avatarLabel.x = this._label.x;
avatarLabel.y = this._label.y;
avatarLabel.width = this._label.width;
avatarLabel.height = this._label.height;
avatarLabel.text = this._label.text;
avatarContainer.addChild(avatarBg);
avatarContainer.addChild(avatarLabel);
var dragData:DragData = new DragData();
dragData.setDataForFormat(LIST_ITEM_DRAG, this._data);
DragDropManager.startDrag(this, touch, dragData, avatarContainer, -avatarLabel.width + 75, 0);
}
else if(touch.phase == TouchPhase.ENDED)
{
stopScrolling();
this._touchID = -1;
this._bgQuad.color = starling.utils.Color.RED;
}
}
else
{
touch = event.getTouch(this, TouchPhase.BEGAN);
if(!touch || touch.target == this || touch.target == this._background)
{
return;
}
this._touchID = touch.id;
this._draggedObject = touch.target;
}
event.stopPropagation();
}
private var _background:Quad;
private var _touchID:int = -1;
private var _draggedObject:DisplayObject;
//================================================================================================
//================================================================================================
//drop interface
//================================================================================================
private function dragEnterHandler(event:DragDropEvent, dragData:DragData):void
{
if(!dragData.hasDataForFormat(LIST_ITEM_DRAG))
{
return;
}
DragDropManager.acceptDrag(this);
}
private function dragMoveHandler(event:DragDropEvent, dragData:DragData):void
{
var dataBeingDragged:Object = dragData.getDataForFormat(LIST_ITEM_DRAG);
if(dataBeingDragged != this._data)
{
if(event.localY < (this.height / 2))
{
this._hiliteTop.visible = true;
this._hiliteBottom.visible = false;
}
else
{
this._hiliteTop.visible = false;
this._hiliteBottom.visible = true;
}
}
}
private function dragExitHandler(event:DragDropEvent, dragData:DragData):void
{
this._label.text = this._data.text;
this._hiliteTop.visible = false;
this._hiliteBottom.visible = false;
}
private function dragDropHandler(event:DragDropEvent, dragData:DragData):void
{
var dataBeingDragged:Object = dragData.getDataForFormat(LIST_ITEM_DRAG);
if(dataBeingDragged != this._data)
{
this.owner.dataProvider.removeItem(dataBeingDragged);
var indexToDragTo:int = this.owner.dataProvider.getItemIndex(this.data);
if(this._hiliteBottom.visible)
indexToDragTo++;
this.owner.dataProvider.addItemAt(dataBeingDragged, indexToDragTo);
this._hiliteTop.visible = false;
this._hiliteBottom.visible = false;
}
stopScrolling();
}
//================================================================================================
//================================================================================================
//Item renderer code
//================================================================================================
protected var _index:int = -1;
public function get index():int
{
return this._index;
}
public function set index(value:int):void
{
if(this._index == value)
{
return;
}
this._index = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
protected var _owner:List;
public function get owner():List
{
return this._owner;
}
public function set owner(value:List):void
{
if(this._owner == value)
{
return;
}
this._owner = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
protected var _data:Object;
public function get data():Object
{
return this._data;
}
public function set data(value:Object):void
{
if(this._data == value)
{
return;
}
this._data = value;
this.invalidate(INVALIDATION_FLAG_DATA);
}
protected var _isSelected:Boolean;
public function get isSelected():Boolean
{
return this._isSelected;
}
public function set isSelected(value:Boolean):void
{
if(this._isSelected == value)
{
return;
}
this._isSelected = value;
this.invalidate(INVALIDATION_FLAG_SELECTED);
this.dispatchEventWith(Event.CHANGE);
}
protected var _label:Label;
protected var _bgQuad:Quad;
protected var _hiliteTop:Quad;
protected var _hiliteBottom:Quad;
protected var _dragHandle:Quad;
protected var _dragHandleButton:starling.display.Button;
override protected function initialize():void
{
this._bgQuad = new Quad(1, 1, starling.utils.Color.SILVER);
this._bgQuad.alpha = 0.5;
this.addChild(_bgQuad);
this._label = new Label();
this.addChild(this._label);
this._hiliteTop = new Quad(100, 2, starling.utils.Color.YELLOW);
this._hiliteTop.visible = false;
this.addChild(_hiliteTop);
this._hiliteBottom = new Quad(100, 2, starling.utils.Color.YELLOW);
this._hiliteBottom.visible = false;
this.addChild(_hiliteBottom);
var dragHandleTexture:Texture = Texture.fromBitmap(new DragHandle());
var dragHandleDownTexture:Texture = Texture.fromBitmap(new DragHandleDown());
_dragHandleButton = new starling.display.Button(dragHandleTexture, "", dragHandleDownTexture);
this.addChild(_dragHandleButton);
_dragHandleButton.addEventListener(TouchEvent.TOUCH, touchHandler);
}
protected function commitData():void
{
if(this._data)
{
this._label.text = this._data.text;
}
else
{
this._label.text = null;
}
}
protected var _padding:Number = 5;
public function get padding():Number
{
return this._padding;
}
public function set padding(value:Number):void
{
if(this._padding == value)
{
return;
}
this._padding = value;
this.invalidate(INVALIDATION_FLAG_LAYOUT);
}
protected function autoSizeIfNeeded():Boolean
{
var needsWidth:Boolean = isNaN(this.explicitWidth);
var needsHeight:Boolean = isNaN(this.explicitHeight);
if(!needsWidth && !needsHeight)
{
return false;
}
this.explicitHeight = 50;
this._label.width = this.explicitWidth - 2 * this._padding;
this._label.height = this.explicitHeight - 2 * this._padding;
this._label.validate();
var newWidth:Number = this.explicitWidth;
if(needsWidth)
{
newWidth = this._label.width + 2 * this._padding;
}
var newHeight:Number = this.explicitHeight;
if(needsHeight)
{
newHeight = this._label.height + 2 * this._padding;
}
return this.setSizeInternal(newWidth, newHeight, false);
}
override protected function draw():void
{
var dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
if(dataInvalid)
{
this.commitData();
}
this.autoSizeIfNeeded();
this.layoutChildren();
}
protected function layoutChildren():void
{
this._label.width = this.actualWidth - (2 * this._padding);
this._label.height = this.actualHeight - (2 * this._padding);
this._label.x = this._padding;
this._label.y = 15;//(this.actualHeight / 2) - (this._label.height / 2);
this._bgQuad.x = this._padding;
this._bgQuad.y = this._padding;
this._bgQuad.width = this.actualWidth - (2 * this._padding);
this._bgQuad.height = this.actualHeight - (2 * this._padding);
this._hiliteTop.x = 0;
this._hiliteBottom.x = 0;
this._hiliteTop.y = 0;
this._hiliteBottom.y = this.height; //this.height - this._hiliteBottom.height;
this._hiliteTop.width = this.width;
this._hiliteBottom.width = this.width;
this._dragHandleButton.x = this.width - this._dragHandleButton.width;
this._dragHandleButton.y = (this.height / 2) - (this._dragHandleButton.height / 2);
}
//================================================================================================
}
}