开发者

What is the preferred way to do a mouse rollover/rollout detection in Flash with AS3

Suppose we have a stage with two squares, like so:

What is the preferred way to do a mouse rollover/rollout detection in Flash with AS3

Suppose we'd like the yellow square to be initially hidden, and we'd like that as long as the mouse cursor is inside the bounds of the red square - the yellow square will be visible, and as long as the mouse cursor is out of the bounds of the red square - that the yellow square will be hidden.

The intuitive approach is to write something like this:

inSqr.visible = false;
outSqr.addEventListener (MouseEvent.ROLL_OVER,sqrOver);
outSqr.addEventListener (MouseEvent.ROLL_OUT,sqrOut);

function sqrOver(e:MouseEvent) {
    inSqr.visible = true;
}

function sqrOut (e:MouseEvent) {
    inSqr.visible = false;
}

With this code, however - any time you move the mouse cursor to within the yellow square - it, apparently, counts as a ROLL_OUT for the RED square - thus the sqrOut function is triggered - making the yellow square disappear, and once the yellow square is not there - the cursor is suddenly within the bounds of the RED square again - so the sqrOver function gets called - bringing back the yellow square's visibility - triggering sqrOut and so on and so forth, thus creating a "flickering" yellow square when the mouse-cursr is over him: the yellow square disappears and reappears repeatedly over and over again.

A possible "fix" for this is to remove the listener for the red's roll-out event while the cursor is inside the yellow (if it's inside the yellow it surely is inside开发者_如何学编程 the red as well), and bring it back when it is out, by adding this to the code above:

 inSqr.addEventListener (MouseEvent.ROLL_OVER,insqrOver);
 inSqr.addEventListener (MouseEvent.ROLL_OUT,insqrOut);
 function insqrOver(e:MouseEvent) {
     if (outSqr.hasEventListener (MouseEvent.ROLL_OUT)) {
         outSqr.removeEventListener(MouseEvent.ROLL_OUT,sqrOut);
     }
     inSqr.visible = true;
 }
 function insqrOut(e:MouseEvent) {
     if (!outSqr.hasEventListener (MouseEvent.ROLL_OUT)) {
         outSqr.addEventListener(MouseEvent.ROLL_OUT,sqrOut);
     }
 }

This works. But it is cumbersome. You have to do it for each any object inside the bounds of the red square - resulting in long code and many event listeners and continuous listener-registration and unregisteration.

A few years ago someone suggested to me this technique:

 outSqr.addEventListener (Event.ENTER_FRAME,hoverCheck);

 function hoverCheck (e:Event) {
     if (e.currentTarget.hitTestPoint(stage.mouseX,stage.mouseY,true)) {
         inSqr.visible = true;
     }
     else {
         inSqr.visible = false;
     }
 }

This is a simple short code that works. But, if your project doesn't really need to use the ENTER_FRAME event it creates the unnecessary overhead and cpu-cycles of repeatedly running the hit test. Also, if the red square covers the entire stage (has the same dimensions as the stage) - it creates problems (it doesn't work).

Is anyone aware of a simple elegant way to accomplish this - one that would not involve too cumbersome and long code and that would not have to use a repeated timer that hit-tests over and over again...?


Place the yellow square inside the red square.

outSqr.addChild(inSqr);

That will solve your problems nicely and simply. Just be sure outSqr is an instance of the Sprite or MovieClip class.


I don't know if this helps in your case, but you could also disable mouse actions of the inSqr, then you can hover over the yellow square which does not trigger the ROLL_OUT

inSqr.mouseEnabled = false

..then you could just use this:

inSqr.visible = false;
outSqr.addEventListener (MouseEvent.ROLL_OVER,sqrOver);
outSqr.addEventListener (MouseEvent.ROLL_OUT,sqrOut);

function sqrOver(e:MouseEvent) {
    inSqr.visible = true;
}

function sqrOut (e:MouseEvent) {
    inSqr.visible = false;
}


the simpliest solution i can imagine:

package {
    import flash.events.MouseEvent;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        private var inner:Sprite;
        private var outer:Sprite;
        public function FlashTest() {
            outer = giveRect(200, 200, 0xff0000);
            addChild(outer);
            inner = giveRect(50, 50, 0xffff00);
            addChild(inner);
            inner.x = inner.y = 75;
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);       
        }

        private function giveRect(w:int, h:int, color:int):Sprite{
            var spr:Sprite =  new Sprite();
            spr.graphics.beginFill(color);
            spr.graphics.drawRect(0, 0, w, h);
            spr.graphics.endFill();
            return spr;            
        }

        private function onMove(e:MouseEvent):void{
            inner.visible = stage.mouseX > outer.x &&
                            stage.mouseX < outer.x + outer.width &&
                            stage.mouseY > outer.y &&
                            stage.mouseY < outer.y + outer.height;
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜