Binyy Wuhan

i love Flex i come from Wuhan

导航

Flex【原创】模拟Android图案解锁

Flex 实现Android图案解锁功能

 

看见Andorid系统里面有图案解锁的功能,试想能用Flex的移动开发实现吗?答案是:完全可以!

环境:Flex 4.6(air3.2)

先看我的包结构:

 

第一视图Sample_Locked2View:

View Code
<?xml version="1.0" encoding="utf-8"?>
<!--TEST APPLICATION 's first view-->
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" title="主页视图"
        xmlns:view="com.yyf.view.*" actionBarVisible="false">
    <s:layout>
        <s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/>
    </s:layout>
    <fx:Script>
        <![CDATA[
            import com.yyf.model.MainDataModel;
            import com.yyf.util.Tools;
            [Bindable]private var mainModel:MainDataModel = MainDataModel.getInstance();
        ]]>
    </fx:Script>
    <view:LockedView id="lock" horizontalCenter="0" verticalCenter="0" creationComplete="mainModel.hotArea = (new Tools()).getHotArea(lock);"/>
    <s:Label id="notice" text="Your Password : {mainModel.password}" visible="{mainModel.successCreated}"/>
    <!--display the HOT_AREA-->
<!--    <s:Label backgroundAlpha="0.3" backgroundColor="0xFED913" 
             x="{mainModel.hotArea.min_x}" y="{mainModel.hotArea.min_y}"
             width="{mainModel.hotArea.max_x - mainModel.hotArea.min_x}"
             height="{mainModel.hotArea.max_y - mainModel.hotArea.min_y}"/>-->
</s:View>

 

核心逻辑类Circle,用于处理绘图相关计算:

View Code
package com.yyf.element
{
    import com.yyf.event.PasswordCreateEevent;
    import com.yyf.model.MainDataModel;
    import com.yyf.util.Config;
    import com.yyf.view.LockedView;
    
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.FocusEvent;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    
    import mx.core.FlexGlobals;
    import mx.core.UIComponent;
    import mx.events.FlexEvent;
    
    import spark.components.Application;
    
    /**
     *<br>Circle UI</br>
     * @author yao yf
     * 2012-04-19
     * */
    public class Circle extends UIComponent
    {
        
        /**radius of the circle**/
        public var radius:Number;
        /**color of the circle**/
        public var color:uint;
        /**index ofd the circle**/
        public var index:int = 0;
        
        /**
         * @private
         **/
        //selected color
        private var selectedColor:uint;
        //current Circle target
        private var target:Circle;
        //line
        private var line:Line = Line.getInstance();
        //temp line
        private var linetmp:LineTemp = LineTemp.getInstance();
        //current start point for draw temp line
        private var currentStaPoint:Point = new Point();
        //has excute the FUNCTION  drawLine()
        private var hasLine:Boolean = false;
        //has excute the FUNCTION circleChange()
        private var hasCircleChanged:Boolean = false;
        //model data
        private var mainModel:MainDataModel = MainDataModel.getInstance();
        //main application
        private static const MAIN_APP:Application = FlexGlobals.topLevelApplication as Application;
        
        /**
         * Constructor
         * @param radius:Number
         * @param color:uint
         * **/
        public function Circle(radius:Number,color:uint)
        {
            super();
            this.radius = radius;
            this.color = color;
            this.draw();
            addListener();
            mainModel.notice = Config.DEFUALT;
        }
        
        //draw
        private function draw():void{
            this.graphics.clear();
            this.graphics.beginFill(color);
            this.graphics.drawCircle(this.radius,this.radius,this.radius);
        }
        
        //add Event Listener
        private function addListener():void{
            this.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
        }
        
        //onMouseDown Handler
        private function onMouseDown(event:MouseEvent):void
        {    
            mainModel.notice = Config.DURING;
            target = event.target as Circle;
            circleChange(target);
            currentStaPoint = new Point(target.x + radius,target.y + radius);
            mainModel.dispatched = false;
            MAIN_APP.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
            MAIN_APP.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
        }
        
        //onMouseMove Handler
        private function onMouseMove(event:MouseEvent):void
        {
            target = event.target as Circle;
            if(target){
                circleChange(target);
                currentStaPoint = new Point(target.x + radius,target.y + radius);
            }else{
                if(event.target is Application)return;
                //                var stagePoint:Point = new Point(event.stageX,event.stageY);
                //                trace(stagePoint.x+" =,= "+stagePoint.y);
                drawTmpLine(target);
            }
        }
        
        //onMouseUp Handler
        private function onMouseUp(event:MouseEvent):void
        {
            MAIN_APP.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
            MAIN_APP.removeEventListener(MouseEvent.MOUSE_UP,onMouseUp);
            mainModel.enable = false;
            linetmp.clear();
            if(!mainModel.dispatched){
                mainModel.dispatchEvent(new PasswordCreateEevent(PasswordCreateEevent.EVT_PASSWORD_CREATED,mainModel.password));
            }
            mainModel.dispatched = true;
        }
        
        //circleChange
        //add a orange small circle on this center
        protected function circleChange(target:Circle):void{
            if(!target)return;
            if(!target.hasCircleChanged){
                target.graphics.beginFill(0xFF5D18);
                target.graphics.drawCircle(this.radius,this.radius,this.radius/2);
                if(!target.hasLine){
                    drawLine(target);
                }
                target.hasCircleChanged = true;
            }
        }
        
        /**
         * draw line path with mouse move
         * @param target:Circle
         * **/
        protected function drawLine(target:Circle):void{
            linetmp.clear();
            line.graphics.lineStyle(Line.THINKNESS,Line.COLOR);
            var c_point:Point;
            if(target == this){
                //                c_point = localToGlobal(new Point(this.x,this.y));
                line.graphics.moveTo(this.x + radius,this.y + radius);
            }else{
                //                c_point = localToGlobal(new Point(target.x,target.y));
                line.graphics.lineTo(target.x + radius,target.y + radius);
            }
            target.hasLine = true;
            mainModel.password += target.index + "";
        }
        
        /**
         * draw temp line path with mouse move
         * @param target:Circle
         * @param stagePoint:Point
         * **/
        protected function drawTmpLine(target:Circle):void{
            //            var currentMovPoint:Point = localToGlobal(new Point(owner.mouseX,owner.mouseY));
            //            trace(currentMovPoint.x + " =,= " + currentMovPoint.y);
            //            if(currentMovPoint.x > mainModel.hotArea.min_x && currentMovPoint.x < mainModel.hotArea.max_x 
            //                && currentMovPoint.y > mainModel.hotArea.min_y && currentMovPoint.y < mainModel.hotArea.max_y)
            //            {
            //            trace(owner.mouseX + " , " + owner.mouseY);
            //            trace(owner.width + " , " + owner.height);
            if(owner.mouseX > 6 && owner.mouseX < (owner.width - 6)
                && owner.mouseY > 6 && owner.mouseY < (owner.height - 6))
            {
                linetmp.clear();
                linetmp.graphics.lineStyle(Line.THINKNESS,Line.COLOR);
                linetmp.graphics.moveTo(currentStaPoint.x , currentStaPoint.y);
                linetmp.graphics.lineTo(owner.mouseX,owner.mouseY);
            }
        }
        
        //get color String from ower pixel
        private function getColorString():String{
            var tmpDta:BitmapData = new BitmapData(owner.width, owner.height);
            tmpDta.draw(owner);
            selectedColor = tmpDta.getPixel(owner.mouseX,owner.mouseY);
            var colorDisplay:String = selectedColor.toString(16).toLocaleUpperCase();
            if(colorDisplay.length < 6){
                switch(colorDisplay.length){
                    case 1 : colorDisplay = "00000" + colorDisplay;break;
                    case 2 : colorDisplay = "0000" + colorDisplay;break;
                    case 3 : colorDisplay = "000" + colorDisplay;break;
                    case 4 : colorDisplay = "00" + colorDisplay;break;
                    case 5 : colorDisplay = "0" + colorDisplay;break;
                    default : break;
                }
            }
            return colorDisplay;
        }
        
    }
}

 

线对象Line(SingleTon):

View Code
package com.yyf.element
{
    import mx.core.UIComponent;
    
    /**
     *<br>Line UI</br>
     * SingleTon
     * @author yao yf
     * 2012-04-19
     * */
    public class Line extends UIComponent
    {
        private static var model:Line;
        
        public static const THINKNESS:Number = 25;
        public static const COLOR:uint = 0xFF5D18;
        
        public function clear():void{
            this.graphics.clear();
        }
        
        public function Line(singletonclass:SingleTonClass)
        {
            if(model != null){
                throw new Error("SingleTon!");
            }
        }
        
        public static function getInstance():Line{
            if(model == null){
                model = new Line(new SingleTonClass());
            }
            return model;
        }
    }
}

class SingleTonClass{}

 

临时线对象LineTemp(SingleTon)此对象为绘制过程中的临时线路径,绘制完成后将被清除:

View Code
package com.yyf.element
{
    import mx.core.UIComponent;
    
    /**
     *<br>Temp Line UI</br>
     * SingleTon
     * @author yao yf
     * 2012-04-19
     * */
    public class LineTemp extends UIComponent
    {
        private static var model:LineTemp;
        
        public static const THINKNESS:Number = 25;
        public static const COLOR:uint = 0xFF5D18;
        
        public function clear():void{
            this.graphics.clear();
        }
        
        public function LineTemp(singletonclass:SingleTonClass)
        {
            if(model != null){
                throw new Error("SingleTon!");
            }
        }
        
        public static function getInstance():LineTemp{
            if(model == null){
                model = new LineTemp(new SingleTonClass());
            }
            return model;
        }
    }
}

class SingleTonClass{}

 

核心视图类LockedView,用于呈图案解锁图面板:

View Code
<?xml version="1.0" encoding="utf-8"?>
<!--
Locked Component
==========================
Explain:custom component for Locked
==========================
Code by yyf 2012-04-19
-->
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
         xmlns:s="library://ns.adobe.com/flex/spark" 
         xmlns:mx="library://ns.adobe.com/flex/mx"
         width="275" height="350"
         creationComplete="creationCompleteHandler(event)">
    <fx:Script>
        <![CDATA[
            import com.yyf.element.Circle;
            import com.yyf.element.Line;
            import com.yyf.element.LineTemp;
            import com.yyf.event.PasswordCreateEevent;
            import com.yyf.model.MainDataModel;
            import com.yyf.util.Config;
            
            import mx.collections.ArrayCollection;
//            import mx.controls.Alert;
            import mx.events.FlexEvent;
            
            /**
             * @prvate
             * **/
            private const RADIUS:Number = 30;
            private const COLOR:uint = 0xFED913;
            //store the Circles
            private static var circleData:ArrayCollection;
            //line path
            private var line:com.yyf.element.Line = com.yyf.element.Line.getInstance();
            //temp line path
            private var linetmp:LineTemp = LineTemp.getInstance();
            //model data
            [Bindable]private var mainModel:MainDataModel = MainDataModel.getInstance();
            
            /**init**/
            private function creationCompleteHandler(event:FlexEvent):void
            {
                mainModel.addEventListener(PasswordCreateEevent.EVT_PASSWORD_CREATED,onCreated);
                displayCircle();
            }
            
            /**display nine Circles**/
            private function displayCircle():void{
                circleData = new ArrayCollection();
                line.includeInLayout = false;
                linetmp.includeInLayout = false;
                this.circles.addElement(line);
                this.circles.addElement(linetmp);
                for(var i:int = 0 ; i < 9 ; i++){
                    var c:Circle = new Circle(RADIUS,COLOR);
                    c.index = (i+1);
                    this.circles.addElement(c);
                    circleData.addItem(c);
                }
            }
            
            /**remove all of the circles group's elements**/
            private function removeCircle():void{
                circleData.removeAll();
                circleData.refresh();
                circleData = null;
                var i:int = this.circles.numElements;
                while(i >= 1){
                    this.circles.removeElementAt(0);
                    i--;
                }
            }
            
            /**RESET button handler**/
            private function reset_clickHandler(event:MouseEvent):void
            {
                mainModel.successCreated = false;
                mainModel.enable = true;
                mainModel.password = "";
                line.clear();
                linetmp.clear();
                removeCircle();
                displayCircle();
            }
            
            /**GO buton handler**/
            private function go_clickHandler(event:MouseEvent):void
            {
//                Alert.show("Your Password : " + mainModel.password);
                trace("Your Password : " + mainModel.password);
            }
            
            //PasswordCreateEevent.EVT_PASSWORD_CREATED call back handler
            private function onCreated(event:PasswordCreateEevent):void
            {
                var pw:String = event.password;
                if(pw.length < 4){
                    mainModel.notice = Config.ERROR;
                    mainModel.successCreated = false;
                    trace("Your Password's lenth can not less than 4 !");
                }else{
                    mainModel.notice = Config.SUCCESS;
                    mainModel.successCreated = true;
                }
            }
            
        ]]>
    </fx:Script>
    <fx:Declarations>
    </fx:Declarations>
    <s:VGroup width="100%" height="100%" horizontalAlign="center" verticalAlign="middle" paddingBottom="5" paddingTop="5" paddingLeft="5" paddingRight="5">
        <s:Label id="noticelbl" text="{mainModel.notice}"/>
        <s:Line xFrom="0" xTo="260">
            <s:stroke>
                <s:SolidColorStroke color="{COLOR}" weight="2" caps="square"/>
            </s:stroke>
        </s:Line>
        <s:Group id="circles" width="100%" height="100%" enabled="{mainModel.enable}">
            <s:layout>
                <s:TileLayout horizontalGap="90" verticalGap="90" requestedColumnCount="3" requestedRowCount="3"
                              paddingLeft="10" paddingTop="10"/>
            </s:layout>
        </s:Group>
        <s:Line xFrom="0" xTo="260">
            <s:stroke>
                <s:SolidColorStroke color="{COLOR}" weight="2" caps="square"/>
            </s:stroke>
        </s:Line>
        <s:HGroup height="35">
            <s:Button id="reset" label="Reset" width="70" height="35" click="reset_clickHandler(event)"/>
            <s:Button id="go" label="Go" width="70" height="35" click="go_clickHandler(event)" enabled="{mainModel.successCreated}"/>
        </s:HGroup>
    </s:VGroup>
</s:BorderContainer>

 

下面是效果图:

 

废话少说,本人一贯作风——崇尚开源,附源码下载地址:

 

https://files.cnblogs.com/loveFlex/Sample_Locked2.rar

 

欢迎大家留言~

posted on 2012-04-24 09:58  Binyy_Wuhan  阅读(2371)  评论(4编辑  收藏  举报