1 Reply Latest reply on Nov 8, 2011 5:05 PM by tykiim

    Scroll-dragging... losing data when itemRenderer is recycled

    tykiim

      I have a HorizontalList that I have modified to support this concept of "push scrolling." The idea is that when the user drags something to the edge of the list, it will scroll to the next item, and so on until the mouse moves back to the main content area.

       

      The itemRenderer is a DataGrid that has dragMove enabled, and the push scrolling works fine after being adapted from the internal dragScroll() functionality. However, if I have 10 items and only 4 are visible, dragging from the first item to the last has some interesting behavior. I think because I push scroll to the end of the list (while the DragManager is doing the drag), the item I am dragging from (the initiator) is recycled/nullified by the time I get to the end of the list. Even though the drag data is a copy, it is still null when I try to use the dragSource dataForFormat function.

       

      I have tried overring the dragStart function in the table to put the dragSource into a static "proxy", but that doesn't work either...same results. In the code sample below, "items" is an empty array in both cases.

       

                 

      override protected function dragDropHandler(event:DragEvent):void {
                      if(event.action == DragManager.COPY) {
                          event.preventDefault();
                      }
                      
                      super.dragDropHandler(event);
                      
                      var items:* = event.dragSource.dataForFormat(event.dragSource.formats[0]);
                      
                      var ds:DragSource = sandbox.dragProxy["test"];
                      
                      items = ds.dataForFormat(ds.formats[0]);
                  }
                  
                  override protected function dragStartHandler(event:DragEvent):void {
                      event.preventDefault();
                      
                      var ds:DragSource = new DragSource();
                      addDragData(ds);
                      
                      sandbox.dragProxy["test"] = ds;
                      
                      DragManager.doDrag(this, ds, event, dragImage, 0, 0, 0.5, dragMoveEnabled);
                  }
      

       

       

       

      So that brings me here. I am not inclined to programmatically create tables inside an HBox to reproduce a "list-like" layout, but I don't see a way around the renderer recycling system...

       

       

       

       

       

      PushScrollHList:

      package {
          import flash.events.MouseEvent;
          import flash.utils.clearInterval;
          import flash.utils.setInterval;
          
          import mx.controls.HorizontalList;
          import mx.core.mx_internal;
          import mx.events.ScrollEvent;
          import mx.events.ScrollEventDetail;
          import mx.events.ScrollEventDirection;
          import mx.managers.DragManager;
          
          use namespace mx_internal;
          
          public class PushScrollHList extends HorizontalList {
              public function PushScrollHList() {
                  super();
              }
              
              /**
               * Handles the system MouseUp event
               **/
              protected function onMouseUp(event:MouseEvent):void {
                  resetDragScrolling();
              }
              
              /** @inheritDoc **/
              override protected function createChildren():void {
                  super.createChildren();
                  
                  systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
              }
              
              /**
               * Overrides drag scrolling to support automatic horizontal list scrolling while performing a drag/drop operation
               * 
               * @copy mx.controls.listClasses.ListBase#dragScroll
               **/
              override protected function dragScroll():void {
                  clearInterval(dragScrollingInterval);
                  
                  // sometimes, we'll get called even if interval has been cleared
                  if(dragScrollingInterval == 0)
                      return;
                  
                  var slop:Number = viewMetrics.left + columnWidth;
                  var scrollInterval:Number = 250;
                  var oldPosition:Number;
                  var scrollEvent:ScrollEvent;
                  
                  oldPosition = horizontalScrollPosition;
                  
                  scrollEvent = new ScrollEvent(ScrollEvent.SCROLL);
                  scrollEvent.detail = ScrollEventDetail.THUMB_POSITION;
                  scrollEvent.direction = ScrollEventDirection.HORIZONTAL;
                  
                  if(mouseX < slop) {
                      horizontalScrollPosition = Math.max(0, oldPosition - 1);
                      
                      dragScrollingInterval = setInterval(dragScroll, scrollInterval);
                      
                      if(oldPosition != horizontalScrollPosition) {
                          scrollEvent.position = horizontalScrollPosition;
                          scrollEvent.delta = horizontalScrollPosition - oldPosition;
                          dispatchEvent(scrollEvent);
                      }
                  } else if(mouseX > (unscaledWidth - slop)) {
                      horizontalScrollPosition = Math.min(maxHorizontalScrollPosition, horizontalScrollPosition + 1);
                      
                      dragScrollingInterval = setInterval(dragScroll, scrollInterval);
                      
                      if(oldPosition != horizontalScrollPosition) {
                          scrollEvent.position = horizontalScrollPosition;
                          scrollEvent.delta = horizontalScrollPosition - oldPosition;
                          dispatchEvent(scrollEvent);
                      }
                  } else {
                      dragScrollingInterval = setInterval(dragScroll, 15);
                  }
                  
                  if(DragManager.isDragging && lastDragEvent && oldPosition != horizontalScrollPosition) {
                      dragOverHandler(lastDragEvent);
                  }
              }
              
              /** @inheritDoc **/
              override protected function mouseDownHandler(event:MouseEvent):void {
                  super.mouseDownHandler(event);
                  
                  if(dragScrollingInterval == 0)
                      dragScrollingInterval = setInterval(dragScroll, 15);
              }
          }
      }
      


        • 1. Re: Scroll-dragging... losing data when itemRenderer is recycled
          tykiim Level 1

          I have updated the drag handlers and it's working a little better...

           

                      override protected function dragDropHandler(event:DragEvent):void {
                          if(event.action == DragManager.COPY) {
                              event.preventDefault();
                          }
          
                          super.dragDropHandler(event);
          
                          var items:* = event.dragSource.dataForFormat("items");
                      }
          
                      override protected function dragStartHandler(event:DragEvent):void {
                          event.preventDefault();
          
                          var ds:DragSource = new DragSource();
                          ds.addData(copySelectedItems(), "items");
          
                          DragManager.doDrag(this, ds, event, dragImage, 0, 0, 0.5, dragMoveEnabled);
                      }
          

           

          By using ds.addData explicitly in the start handler, the drag data is not getting lost when the item renderer is recycled. However, this breaks the dragMove behavior, because the original table retains the data that was dragged... so it's essentially a copy method, rather than the desired move behavior.

           

          Will continue to work on getting the move behavior back, but please chime in if you have any suggestions