自定義view——仿京東手勢解鎖

Ali31Q 7年前發布 | 6K 次閱讀 安卓開發 Android開發 移動開發

先直接上效果吧。

京東金融手勢解鎖

如何使用呢?

(1)對象的獲取并設置正確的密碼

mUnLockView = (UnLockView) findViewById(R.id.unlockview);
    mUnLockView.setmRightPsw("14789");

(2)然后在當前Activity或者Fragment中實現 UnLockView.ResponseInput接口。例子如下:

@Override
public void inputOK() {
    //TODO
    Toast.makeText(this, "密碼正確", Toast.LENGTH_SHORT).show();
}

@Override
public void inputErr() {
    //TODO
    Toast.makeText(this, "密碼錯誤", Toast.LENGTH_SHORT).show();
}

自定義view(viewgroup)的步驟就是下面這個樣子,很官方呢。

我們的主要工作在onMeasure()和onDraw()中。在onMeasure()中負責測量view的大小,在onDraw()中負責view的繪制。

觀察效果為9個圓,在未點擊時為灰色,在點擊或者劃過的時候將背景變為藍色并畫連線,在該圓外圍畫一個藍色線條的大圓。確實很簡單,但是在實際的過程中遇到了幾個問題,分享一下。

1.對象的存儲

static class Circle{

    private int x;//x坐標
    private int y;//y坐標
    private int innderRadius; //小圓半徑
    private int outterRadius; //大圓半徑
    private boolean isClicked; //是否點擊
}

當某個圓被劃過或者被點擊的時候,將isClicked置為true。

2.線條的繪制

我用path存儲用戶手勢的路徑,從點擊屏幕到手指抬起為止。在畫圓與圓之間的線條時又有所不同,涉及到一個小知識點與大家分享下。那就是Path的lineTo與setLastPoint方法的區別。先看下使用lineTo的效果。

因為onTouchEvent是個回調方法,會不停被系統回調,所以如果用lineTo這個方法的話,因為坐標不停地變會畫出曲線來,這個時候我們就需要用另外一個方法setLastPoint,這個會改變上一次繪制的點的位置,所以會畫出一條直線來。

3.如何判斷輸入是否正確

用一個StringBuilder對象保存用戶的輸入數據,當用戶手指抬起來時對比輸入的內容與正確的密碼,并告知用戶。那么如何采集用戶的輸入呢?我們在點擊圓或者劃過某個圓的時候將圓的下標采集。

4.將密碼的判斷結果反饋給用戶

在UnLockView中有個接口ResponseInput,只需要在當前的Activity或者Fragment中實現該接口即可。

public interface ResponseInput{

    public void inputOK();
    public void inputErr();
}

看下核心的代碼吧,發現要將一個東西說明白真的挺難的,讀書人的事就不要多說了,大家直接看代碼吧。

判斷點擊或者劃過的是哪個圓

public int getClickedIndex(float x,float y){

    for(int i=0;i<circles.length;i++){
        Circle cirlce = circles[i];
        if( x >= cirlce.x - cirlce.outterRadius
                && x <= cirlce.x + cirlce.outterRadius
                && y<= cirlce.y + cirlce.outterRadius
                && y >= cirlce.y - cirlce.outterRadius){
            return i;
        }
    }
    return -1;
}

這個里面最重要的就是事件的處理了,我們簡單看看事件處理的代碼吧。

public boolean onTouchEvent(MotionEvent event) {

    int action = event.getAction();
    switch(action){

        case MotionEvent.ACTION_DOWN:{

            int index = getClickedIndex(event.getX(),event.getY());
            if(index >= 0 && index <= circles.length){

                //采集用戶輸入
                gatherInput(index);
                mPath.moveTo(circles[index].x,circles[index].y);
                return true;
            }else{
                //TODO 第一次沒觸到任何塊則提示

                return false;
            }

        }
        case MotionEvent.ACTION_MOVE:{

            float x = event.getX();
            float y = event.getY();
            int index = getClickedIndex(x,y);
            if(index >= 0 && index < circles.length){
                circles[index].isClicked = true;
                //采集用戶輸入
                gatherInput(index);

                //這個地方是為了解決第一次點擊時畫點擊點與點(0,0)的bug
                if(getClickedIndex(mNextX,mNextY) >= 0){
                    mPath.lineTo(circles[index].x,circles[index].y);
                }else{
                    mPath.setLastPoint(circles[index].x,circles[index].y);
                }
                mNextX = circles[index].x;
                mNextY = circles[index].y;
            }else{
                mNextX = x;
                mNextY = y;
                mPath.setLastPoint(mNextX,mNextY);

            }

            invalidate();

        }break;
        case MotionEvent.ACTION_UP:{

            //TODO 判斷密碼是否正確
            if(isInputOK()){

                object.inputOK();

            }else{
                object.inputErr();
            }
            uninit();

        }break;
    }
    return super.onTouchEvent(event);
}

從代碼可以看出來,在MotionEvent.ACTION_DOWN中,我們分別進行了處理,那是因為如果return true的話,之后的MotionEvent.ACTION_UP

與MotionEvent.ACTION_MOVE事件才會被捕獲,如果返回false則不會被捕獲。

還有其他一些模塊簡單介紹下,屬于不重要的部分。

1. 采集用戶的輸入

gatherInput()

2. 判斷輸入是否正確

isInputOK()

3. circles初始化

init()

4. 畫筆的初始化與設置

initResources(Context context)

3. circles反初始化(在MotionEvent.ACTION_UP時調用將circles的isClicked置為false,path清空,input數據清空)

uninit()。

 

 

 本文由用戶 Ali31Q 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!