溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android怎么繪制九宮格解鎖控件

發(fā)布時間:2022-03-29 09:03:52 來源:億速云 閱讀:92 作者:iii 欄目:開發(fā)技術

這篇“Android怎么繪制九宮格解鎖控件”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Android怎么繪制九宮格解鎖控件”文章吧。

自定義控件的代碼如下:

public class LockedView extends View {
 
    private boolean isFirst = true;//設置第一次加載時為true,后面重新畫圖不再執(zhí)行
    private int width, height;//獲取控件的寬度和高度
    private int offsetX, offsetY;//獲取點坐標時的X軸和Y軸的偏移量
    private Point[][] pointList;//每個點的坐標存放的數(shù)組
    private int r;//每個圓的半徑
    private Bitmap map1, map2, map3;//3種狀態(tài)的bitmap
    private float eventX, eventY;//觸摸控件時的X坐標和Y坐標
    private boolean isPressed;//判斷是否觸摸著控件
    private boolean moveOnPoint;//判斷是否移動到一個點上了
    private boolean isFinish;//判斷手勢是否結束
    private List<Point> list = new ArrayList<>();//存放經(jīng)過的點的集合
    private Point checkedPoint;
    private Paint paint;//畫筆
    public static final int LOCKED_FIRST=0;//第一次加載acitivity時設置密碼時的返回值
    public static final int LOCKED_TRUE=1;//解鎖成功時的返回值
    public static final int LOCKED_FALSE=2;//解鎖失敗的返回值
    private OnLockedChangedListener onLocked;//接口回調
 
    public LockedView(Context context, AttributeSet attrs) {
        super(context, attrs);
 
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //判斷是否第一次加載
        if (isFirst) {
            //初始化點坐標
            initPoints();
            //初始化畫筆
            initPaint();
            isFirst = false;
        }
        //根據(jù)每個點的狀態(tài)來畫對應的bitmap
        drawPoints(canvas);
        //畫手勢滑動過程中的線
        drawLines(canvas);
    }
 
    //初始化畫筆
    private void initPaint() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //設置畫筆顏色為藍色
        paint.setColor(getResources().getColor(R.color.LockedColor));
        //設置畫筆的寬度為8
        paint.setStrokeWidth(8);
    }
 
    //畫線
    private void drawLines(Canvas canvas) {
        //如果集合有值
        if (list.size() > 0) {
            //獲得起始點的實例
            Point startPoint = list.get(0);
            for (int i = 1; i < list.size(); i++) {
                //獲得停止點的實例
                Point stopPoint = list.get(i);
                //根據(jù)起始點坐標跟停止點坐標來畫線
                canvas.drawLine(startPoint.getX(), startPoint.getY(), stopPoint.getX(), stopPoint.getY(), paint);
                //把停止點賦值給起始點,這樣每次遍歷的時候起始點都是上一個點
                startPoint = stopPoint;
            }
            //如果沒有移動到一個點上
            if (moveOnPoint == false) {
                //則根據(jù)最后個點的坐標跟當前手勢移動的坐標畫線
                canvas.drawLine(startPoint.getX(), startPoint.getY(), eventX, eventY, paint);
            }
 
        }
    }
 
    //設置觸摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //獲得觸摸的X坐標
        eventX = event.getX();
        //獲得觸摸的Y坐標
        eventY = event.getY();
        //每次觸摸到離開屏幕之前都默認為沒有完成
        isFinish = false;
        //默認移動到點上了
        moveOnPoint = true;
        //選中的點
        checkedPoint = null;
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //如果按下,重置下點
                reset();
                //根據(jù)觸摸的X,Y坐標以及圓的半徑來判斷是否觸摸到了一個圓上,如果有則返回實例,沒有則返回空
                checkedPoint = checkPoint(eventX, eventY, r);
                if (checkedPoint != null) {
                    //如果實例不為空,則設置選中點的狀態(tài)為選中
                    checkedPoint.setState(Point.POINT_XUANZHONG);
                    //第一次按下按到點上時設置為true
                    isPressed = true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                //如果按下在一個點上,就會執(zhí)行移動動作的邏輯
                if (isPressed) {
                    //同上
                    checkedPoint = checkPoint(eventX, eventY, r);
                    if (checkedPoint != null) {
                        checkedPoint.setState(Point.POINT_XUANZHONG);
                        //如果實例不為空,則設置移動到了點上
                        moveOnPoint = true;
                    } else {
                        //否則設置沒有移動到點上
                        moveOnPoint = false;
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                //抬起時,設置第一次按在點上的參數(shù)為false以及完成了觸摸過程
                isPressed = false;
                isFinish = true;
                break;
            case MotionEvent.ACTION_CANCEL:
                isPressed = false;
                isFinish = true;
                break;
        }
        //如果第一下按在了點上并且沒有完成觸摸并且選中的點的實例不為空
        if (isPressed && !isFinish && checkedPoint != null) {
            //判斷這個實例是否在list集合中
            if (isInList(checkedPoint)) {
                //如果在,則設置沒有移動在點上
                moveOnPoint = false;
            } else {
                //否則就添加到集合里面
                list.add(checkedPoint);
            }
            //如果完成了觸摸
        } else if (isFinish) {
            if (list.size() > 0) {
                //如果集合長度為1,則表示只是摸到了一個點,直接重置
                if(list.size()==1){
                    reset();
                    //如果集合長度小于5,則表示密碼太短了不符合要求,把選中的點設置為錯誤狀態(tài),并且通過接口回調返回數(shù)據(jù)
                }else if(list.size()<5){
                    errorPoint();
                    if(onLocked!=null){
                        onLocked.onResult("密碼太短");
                    }
                    //如果集合長度滿足要求,則通過接口的返回值,來判斷不同的情況
                }else if(list.size()>=5){
                    StringBuffer buffer=new StringBuffer();
                    for(int i=0;i<list.size();i++){
                        buffer.append(list.get(i).getIndex());
                    }
                    if(onLocked!=null){
                        switch (onLocked.onPassword(buffer.toString())){
                            //第一次打開activity時,shared里面沒有值,則把當前的密碼存到shared里
                            case LOCKED_FIRST:
                                onLocked.onResult("設置密碼成功");
                                reset();
                                break;
                            //如果shared里面有值,則根據(jù)值對比下當前的密碼值,如果一樣則解鎖成功,不一樣則失敗
                            case LOCKED_TRUE:
                                onLocked.onResult("解鎖成功");
                                reset();
                                break;
                            case LOCKED_FALSE:
                                onLocked.onResult("解鎖失敗");
                                errorPoint();
                                break;
                        }
                        //重新調用onDraw方法
                        postInvalidate();
                        //此次觸摸消費掉
                        return true;
                    }
 
                }
            }
        }
 
        postInvalidate();
        return true;
    }
 
    //設置錯誤的點的狀態(tài)
    private void errorPoint() {
        for(int i=0;i<list.size();i++){
            list.get(i).setState(Point.POINT_XUANCUO);
        }
    }
 
    //判斷點是否在集合里面
    private boolean isInList(Point checkedPoint) {
        return list.contains(checkedPoint);
    }
 
    //根據(jù)觸摸點的X,Y軸坐標以及圓半徑判斷是否觸摸到了一個圓
    private Point checkPoint(float eventX, float eventY, int r) {
        for (int i = 0; i < pointList.length; i++) {
            for (int j = 0; j < pointList[i].length; j++) {
                Point point = pointList[i][j];
                double juli = getPointJuli(eventX, eventY, point.getX(), point.getY());
                if (juli < r) {
                    return point;
                }
            }
        }
        return null;
    }
 
    //重置點
    private void reset() {
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setState(Point.POINT_MOREN);
        }
        list.clear();
    }
 
    //獲取兩點之間的距離
    private double getPointJuli(float eventX, float eventY, int x, int y) {
        return Math.sqrt(Math.abs(eventX - x) * Math.abs(eventX - x) + Math.abs(eventY - y) * Math.abs(eventY - y));
    }
 
 
    //根據(jù)點的狀態(tài)來畫點
    private void drawPoints(Canvas canvas) {
        for (int i = 0; i < pointList.length; i++) {
            for (int j = 0; j < pointList[i].length; j++) {
                Point point = pointList[i][j];
                switch (point.getState()) {
                    case Point.POINT_MOREN:
                        canvas.drawBitmap(map1, point.getX() - r, point.getY() - r, null);
                        break;
                    case Point.POINT_XUANZHONG:
                        canvas.drawBitmap(map2, point.getX() - r, point.getY() - r, null);
                        break;
                    case Point.POINT_XUANCUO:
                        canvas.drawBitmap(map3, point.getX() - r, point.getY() - r, null);
                        break;
                }
            }
        }
    }
 
    //初始化點坐標和bitmap
    private void initPoints() {
        //獲得控件的寬度
        width = getWidth();
        //獲得控件的高度
        height = getHeight();
        //設置X的偏移量為0
        offsetX = 0;
        //設置Y的偏移量為0
        offsetY = 0;
        //如果是豎屏則
        if (width < height) {
            offsetY = (height - width) / 2;
            height = width;
        } else {
            offsetX = (width - height) / 2;
            width = height;
        }
        //創(chuàng)建一個Point數(shù)組存放點的坐標
        pointList = new Point[3][3];
        //設置索引,好判斷密碼
        int index=1;
        //遍歷,用算法算出每個點的坐標
        for (int i = 0; i < pointList.length; i++) {
            for (int j = 0; j < pointList[i].length; j++) {
                pointList[i][j] = new Point(offsetX + width / 4 * (i + 1), offsetY + height / 4 * (j + 1));
                pointList[i][j].setIndex(index);
                index++;
            }
        }
        //設置3個bitmap,分別是默認狀態(tài)的,選中狀態(tài)的,錯誤狀態(tài)的
        map1 = BitmapFactory.decodeResource(getResources(), R.drawable.aa);
        map2 = BitmapFactory.decodeResource(getResources(), R.drawable.bb);
        map3 = BitmapFactory.decodeResource(getResources(), R.drawable.cc);
        //獲得圓的半徑
        r = map1.getWidth() / 2;
    }
 
    public void setOnLockedChangedListener(OnLockedChangedListener onLocked){
        this.onLocked=onLocked;
    }
 
    //設置回調接口
    public interface OnLockedChangedListener{
        public int onPassword(String password);
        public void onResult(String result);
    }
}

activity代碼:

public class LockedActivity extends Activity {
 
    private LockedView lockedView;
    private TextView textView;
    private SharedPreferences preferences;
    private String pass;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_locked);
        //初始化控件
        lockedView= (LockedView) findViewById(R.id.lockedView);
        textView= (TextView) findViewById(R.id.textView);
        //獲得shared
        preferences=getSharedPreferences("Locked",MODE_PRIVATE);
        //根據(jù)存儲在shared里的鍵獲得密碼值
        pass=preferences.getString("password","");
        //如果沒有代表第一次啟動activity,則textview設置文本為情設置密碼,如果不是第一次啟動,則設置文本為請解鎖
        if(pass.equals("")){
            textView.setText("請設置密碼");
        }else{
            textView.setText("請解鎖");
        }
        lockedView.setOnLockedChangedListener(new LockedView.OnLockedChangedListener() {
            @Override
            public int onPassword(String password) {
                //從shared里取值
                pass=preferences.getString("password","");
                //如果值為空,則把接口返回的password存入shared里
                if(pass.equals("")){
                    SharedPreferences.Editor editor=preferences.edit();
                    editor.putString("password",password);
                    editor.commit();
                    textView.setText("請解鎖");
                    return 0;
                }else if(pass.equals(password)){
                    //如果匹配了密碼,則返回數(shù)字1代表解鎖成功
                    return 1;
                }
                //如果不匹配密碼返回2
                return 2;
            }
 
            @Override
            public void onResult(String result) {
                //根據(jù)密碼匹配情況再從接口獲得要toast的數(shù)據(jù)
                Toast.makeText(LockedActivity.this,result,Toast.LENGTH_SHORT).show();
                //數(shù)據(jù)是解鎖成功,則跳轉activity
                if(result.equals("解鎖成功")){
                    Intent intent=new Intent(LockedActivity.this,MainActivity.class);
                    startActivity(intent);
                }
            }
        });
    }
}

布局代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <com.example.chaohengdai.test922.LockedView
        android:id="@+id/lockedView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <TextView
        android:id="@+id/textView"
        android:textSize="20sp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

以上就是關于“Android怎么繪制九宮格解鎖控件”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI