Search code examples
actionscript-3flashscrolltouchmovieclip

Touch scroll on Air for Android in Adobe Flash


I'm trying to make a touch-based scrolling MovieClip with many buttons. I want that button to move according to the movieclip's mouseDown or mouseUp events. I hope someone can help me with this problem.

var maxY:Number = 725;
var minY:Number = 350;
var _startY:Number;
var _startMouseY:Number;
addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);

function mouseDownHandler(event:MouseEvent):void {
    _startY = davies.y;
    _startY = toa.y;
    _startMouseY = mouseY;
    stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMoveHandler, false, 0, true);
    stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler, false, 0, true);
}

function stage_mouseMoveHandler(event:MouseEvent):void {
    var offsetY:Number = mouseY - _startMouseY;
    background_scroll_product.y = Math.max(Math.min(maxY, _startY + offsetY), minY);
    davies.y = Math.max(Math.min(maxY, _startY + offsetY), minY);
    toa.y = Math.max(Math.min(maxY, _startY + offsetY), minY);
}

function stage_mouseUpHandler(event:MouseEvent):void {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMoveHandler);
    stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUpHandler);
}

Before and after scroll :


Solution

  • Solution

    1: Try replacing Math.max(Math.min(maxY, _startY + offsetY), minY); with the following:

    clamp(mouseY - _startY + offsetY, minY, maxY);
    
    function clamp(original:Number, low:Number, high:Number):Number {
        return (original > high) ? high : (original < low) ? low : original;
    }
    

    2: Move all of your content into a single container. It's easier to move a one object, rather than moving many objects.

    Many Objects:

    0:MainTimeline
        0:background_scroll_product //.y += offsetY;
        1:davies                    //.y += offsetY;
        2:toa                       //.y += offsetY;
        ...
    

    One Object:

    0:MainTimeline
        0:container //.y += offsetY;
            0:background_scroll_product
            1:davies
            2:toa
            ...
    

    Demonstration

    Below is code that you can drop into a new project and it will compile with a working scrolling container. Please be mindful that others will likely need a Minimal, Complete, and Verifiable example like this when you ask questions.

    var background_scroll_product, davies, toa;
    demoSetup();
    
    /* ^^^ Omit this if you already have these objects defined ^^^ */
    
    // Create a container for our content.
    var container:Sprite = new Sprite();
    addChild(container);
    
    // Put the content inside the container.
    container.addChild(background_scroll_product);
    container.addChild(davies);
    container.addChild(toa);
    
    // setup the min based on the size of the contents.
    var loc:Object = {
        "max":50,
        "min":stage.stageHeight - container.height
    };
    
    addEventListener("mouseDown", mouseHandler);
    
    function mouseHandler(e:Event):void {
        switch (e.type) {
            case "mouseDown":
                loc.start = mouseY;
                loc.container = container.y;
                addEventListener("mouseUp", mouseHandler);
                addEventListener("mouseMove", mouseHandler);
                break;
            case "mouseUp":
                removeEventListener("mouseUp", mouseHandler)
                removeEventListener("mouseMove", mouseHandler);
                break;
            case "mouseMove":
                // Scroll the container.
                container.y = clamp(mouseY - loc.start + loc.container, loc.min, loc.max);
                break;
        }
    }
    
    function clamp(original:Number, low:Number, high:Number):Number {
        return (original > high) ? high : (original < low) ? low : original;
    }
    
    function demoSetup():void {
        // This sets up a facsimile of the project, to create a Minimal, and Verifiable example.
        var bg:Sprite = new Sprite();
        bg.graphics.beginFill(0xA1A1A1);
        bg.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
        bg.graphics.endFill();
        addChild(bg);
    
        background_scroll_product = new Shape();
        background_scroll_product.graphics.beginFill(0xf0e3e5);
        background_scroll_product.graphics.drawRect(0, 0, 250, 750);
        background_scroll_product.graphics.endFill();
    
        davies = new Shape();
        davies.graphics.beginFill(0x243066);
        davies.graphics.drawRect(0, 0, 200, 400);
        davies.graphics.endFill();
        davies.x = davies.y = 25;
    
        toa = new Shape();
        toa.graphics.beginFill(0xdc3734);
        toa.graphics.drawRect(0, 0, 200, 200);
        toa.graphics.endFill();
        toa.x = 25;
        toa.y = 525;
    }
    

    Response to FLA

    I highly recommend you do not work with scenes, specifically because they create dirty states that are not imminently decipherable. In fact, as you appear to be working towards a mobile app, you should definitely consider using a full-fledge UI framework such as FeathersUI. Regardless...

    Lingering Container

    The Timeline tries to treat each frame as a unique state for the program. You can visually build a UI this way, but it is clunky. Furthermore, as you've discovered, when you mix WYSIWYG with functional programming, there are things that the Flash UI was never aware of and never "cleans up". You manually added addChild(container), and so you're also expected to manually removeChild(container). You could place that inside your listener function for the back button.

    Container hovering over Titlebar

    Consider your Main Menu heiarchy:

    0: instance15 (Shape)
    1: button_back (SimpleButton)
    2: instance16 (StaticText)
    3: container (Sprite)
    

    As you can see, layers 0 through 2 are your top menu objects. Moving container behind the menu is as simple as calling addChildAt(), and setting the second argument to the 0 index.

    addChildAt(container, 0);
    

    Last Images are clipped

    The reason for this is that your content is not positioned at y:0. If you want to fix that, either move the content to start at y:0, or add the offset of your first graphic to the min value...

    "min":this.loaderInfo.height - container.height - davies.y