Android自定View之绘制解锁

最近需要做图案解锁功能,所以自定义了下View发表下以后备用

解锁效果界面

 

解锁失败界面

解锁成功界面

自定义PattenView.class类

public class PattenView extends View{
    private int width;
    private int height;
    private Paint criclepaint;//正常圆
    private Paint cricleTouchpaint;//绘制后的圆
    private Paint cricleLinehpaint;//直线圆
    private int cricleWidht;//圆直径宽度
    private int cricle_space;//圆之间的的间隙
    private Point point;//手势触摸的位置
    private List<Integer> list=new ArrayList<>();//存储绘制的点
    private List<Integer> listResult=new ArrayList<>();//存储被绘画的数字
    private Handler handler;
    private String password;
    public PattenView(Context context) {
        super(context);
        init();
    }



    public PattenView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PattenView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @SuppressLint("NewApi")
    public PattenView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {//初始化代码
        criclepaint = new Paint();
        criclepaint.setAntiAlias(true);
        criclepaint.setColor(Color.WHITE);
        criclepaint.setStrokeWidth(5);
        criclepaint.setStyle(Paint.Style.STROKE);

        cricleTouchpaint = new Paint();
        cricleTouchpaint.setAntiAlias(true);
        cricleTouchpaint.setStrokeWidth(5);
        cricleTouchpaint.setStyle(Paint.Style.FILL);
        cricleTouchpaint.setColor(Color.parseColor("#66ccff"));

        cricleLinehpaint = new Paint();
        cricleLinehpaint.setAntiAlias(true);
        cricleLinehpaint.setStrokeWidth(25);
        cricleLinehpaint.setStyle(Paint.Style.STROKE);
        cricleLinehpaint.setColor(Color.parseColor("#66ccff"));
        cricleLinehpaint.setAlpha(60);

        point = new Point();

        for (int i = 0; i <9 ; i++) {
            list.add(0);
        }
    }

//测绘控件大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
        if (width < height) {//获取最小的宽
            height = width;

        } else {
            width = height;
        }
        cricleWidht = (int) (width / 10);
        cricle_space = width/10;

        cricleLinehpaint.setStrokeWidth(width/50);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

//绘制圆圈
      for (int i = 0; i <3 ; i++) {
            for (int j = 0; j < 3; j++) {
                if (list.get(j * 3 + i) != 0) {//绘制被绘画的圆
                    cricleTouchpaint.setStyle(Paint.Style.STROKE);//绘制外圆
                    canvas.drawCircle(cricle_space * (i * 2 + 1) + cricleWidht * (1 + i), cricle_space * (j * 2 + 1) + cricleWidht * (1 + j), cricleWidht, cricleTouchpaint);
                    cricleTouchpaint.setStyle(Paint.Style.FILL);//绘制圆内小圆圈
                    canvas.drawCircle(cricle_space * (i * 2 + 1) + cricleWidht * (1 + i), cricle_space * (j * 2 + 1) + cricleWidht * (1 + j), cricleWidht/5, cricleTouchpaint);

                } else {//绘制未被绘画的圆
                    canvas.drawCircle(cricle_space*(i*2+1)+cricleWidht*(1+i),cricle_space*(j*2+1)+cricleWidht*(1+j),cricleWidht,criclepaint);

                }
//                canvas.drawCircle(cricle_space*(1+i*2)+cricleWidht*i*2,cricle_space*(1+j*2)+cricleWidht*j*2,cricleWidht,criclepaint);
            }
        }


        //连线路径
        Path path = new Path();
        path.setFillType(Path.FillType.WINDING);
      //绘制连线
        for (int i = 1; i <listResult.size() ; i++) {
            if (i == 1) {
                int numberFist = listResult.get(0)-1;
                path.moveTo(cricle_space * ((numberFist%3) * 2 + 1) + cricleWidht * (1 + (numberFist%3)),
                        cricle_space * ((numberFist/3) * 2 + 1) + cricleWidht * (1 + (numberFist/3)));
            }
            int number = listResult.get(i)-1;
            path.lineTo(cricle_space * ((number%3) * 2 + 1) + cricleWidht * (1 + (number%3)),
                    cricle_space * ((number/3) * 2 + 1) + cricleWidht * (1 + (number/3)));
         //   Log.e("直线" + listResult.get(i), "X=" + number % 3 + "Y=" + number/ 3);
        }
        canvas.drawPath(path,cricleLinehpaint);


        if (point != null&&listResult.size()>0&&listResult.size()<9) {//绘制手势被触摸的动态连线
            path = new Path();
            int number = listResult.get(listResult.size()-1)-1;
            path.moveTo(cricle_space * ((number%3) * 2 + 1) + cricleWidht * (1 + (number%3)),
                    cricle_space * ((number/3) * 2 + 1) + cricleWidht * (1 + (number/3)));
            //Log.e("直线" + listResult.get(listResult.size()-1), "X=" + number % 3 + "Y=" + number/ 3);
            path.lineTo(point.x, point.y);
            canvas.drawPath(path,cricleLinehpaint);
        }
     
}

//触摸后的计算
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                resertDraw();//手势抬起进行重绘
                break;
            case MotionEvent.ACTION_UP://手势按下进行回调或者提示
                String res = "";
                for (int i = 0; i <listResult.size() ; i++) {
                    res +=listResult.get(i);
                }
               /* Toast.makeText(getContext(),"你输入的密码为:"+res,Toast.LENGTH_LONG).show();*/
                if (handler != null &&password!=null &&res.equals(password)) {

                    Message message = new Message();
                    message.what = 200;
                    message.obj = res;
                    handler.sendMessage(message);
                } else if (handler != null &&password!=null &&!res.equals(password)){

                    Message message = new Message();
                    message.what = 404;
                    message.obj = res;
                    handler.sendMessage(message);
                } else if (handler != null) {
                    Message message = new Message();
                    message.what = 200;
                    message.obj = res;
                    handler.sendMessage(message);
                } else {
                    Toast.makeText(getContext(), "快去绘制图案吧", Toast.LENGTH_SHORT).show();
                }


                break;
            case MotionEvent.ACTION_MOVE://手势移动进行绘制手势动作
                point.x = (int) event.getX();
                point.y = (int) event.getY();
                postInvalidate();
                for (int i = 0; i <3 ; i++) {
                    for (int j = 0; j <3 ; j++) {
                        //手势位置判断是否在绘制圆的范围,是的话进行绘制触发的绘制效果
                        if (event.getX() > (cricle_space*(i*2+1)+cricleWidht*(1+i)-cricleWidht)  && event.getX() < (cricle_space*(i*2+1)+cricleWidht*(1+i)+cricleWidht)
                                && event.getY() > (cricle_space*(j*2+1)+cricleWidht*(1+j)-cricleWidht) && event.getY() < (cricle_space*(j*2+1)+cricleWidht*(1+j)+cricleWidht) ) {
                            //Log.e("触摸点", "" + (j * 3 + i+1));
                            list.set(j * 3 + i, 1);

                            for (int k = 0; k <listResult.size() ; k++) {//判断手势是否已经被绘制过
                                if (listResult.get(k) == j * 3 + i + 1) {
                                    return false;
                                }
                            }
                            listResult.add(j * 3 + i + 1);//没被绘制添加到到队列并进行绘制
                            postInvalidate();

                        } else {
                            //Log.e("没有", "" + (i * 3 + j));
                        }
                    }
                }

                break;

        }
        return true;

    }

public  void resertDraw() {//重绘
    listResult = new ArrayList<>();
    for (int i = 0; i <list.size() ; i++) {
        list.set(i, 0);
    }
    postInvalidate();
}

    public void checkTrue(String pwd,Handler handler) {//手势密码校验
        this.handler = handler;
        password = pwd;
    }
    public void getPassword(Handler handler) {//获取密码回调
        this.handler = handler;
    }


    public void setPassword(String pwd) {//手势密码初始化绘制
        resertDraw();
        String[] split = pwd.split("");
        for (int i = 0; i <split.length ; i++) {
            if ((!split[i].equals(""))&&split[i].matches("[0-9]"))
            list.set(Integer.valueOf(split[i])-1, 1);
        }
       postInvalidate();

    }
}

 

 

这个View的使用,xml布局

 

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#3a71b5">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:gravity="center">
        <view.PattenView
            android:id="@+id/patten_view_small"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_margin="5dp"/>

        <TextView
            android:id="@+id/patten_username"
            android:textColor="@color/white"
            android:textSize="20dp"
            android:text="ad**n"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/patten_tip"
            android:layout_marginTop="25dp"
            android:textColor="@color/white"
            android:textSize="18dp"
            android:text="确认解锁图案"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
    <view.PattenView
        android:id="@+id/patten_view"
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/patten_other"
            android:layout_marginLeft="25dp"
            android:layout_marginBottom="20dp"
            android:textColor="@color/white"
            android:textSize="18dp"
            android:text="其他用户登录"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

 

activity的使用

public class PattenSetPwdActivity extends AppCompatActivity {

    private SharedPreferences pre;
    private SharedPreferences.Editor edit;
    private PattenView patten_view_small;
    private TextView patten_username;
    private TextView patten_tip;
    private PattenView patten_view;
    private TextView patten_other;
    private String pwd;
    private int inputTime=0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_patten_pwd);
        pre = getSharedPreferences("data", MODE_PRIVATE);
        edit = pre.edit();

        initView();


    }

    private void initView() {
        patten_view_small = (PattenView) findViewById(R.id.patten_view_small);
        patten_username = (TextView) findViewById(R.id.patten_username);
        patten_tip = (TextView) findViewById(R.id.patten_tip);
        patten_view = (PattenView) findViewById(R.id.patten_view);
        patten_other = (TextView) findViewById(R.id.patten_other);

        patten_username.setText(Util.hintUsername(pre.getString("username","")));

        patten_view.getPassword(new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                patten_view.resertDraw();//密码重绘
                if (msg.obj.toString().trim().length() < 4) {
                    Toast.makeText(PattenSetPwdActivity.this, "密码长度必须大于4", Toast.LENGTH_SHORT).show();
                }else {
                    inputTime++;
                    if (inputTime == 1) {//第一次绘制

                        pwd = msg.obj.toString();
                        patten_tip.setTextColor(Color.WHITE);
                        patten_tip.setText("再输一次");
                        patten_view_small.setPassword(msg.obj.toString());
                    } else if (inputTime == 2) {//第二次绘制
                        inputTime = 0;
                        patten_view_small.resertDraw();

                        if (pwd.equals(msg.obj.toString())) {//密码两次是否一致
                            patten_tip.setTextColor(Color.GREEN);
                            patten_tip.setText("绘制密码成功");
                            edit.putString("patten", msg.obj.toString()).commit();
                            new Handler().postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    startActivity(new Intent(PattenSetPwdActivity.this, MainActivity.class));
                                    finish();
                                }
                            }, 1000);
                        } else {

                            patten_tip.setTextColor(Color.RED);
                            patten_tip.setText("两次密码不一致");
                            TranslateAnimation translateAnimation = new TranslateAnimation(-20, 20, 0, 0);
                            translateAnimation.setRepeatCount(5);
                            translateAnimation.setDuration(1000);
                            patten_tip.setAnimation(translateAnimation);
                            Toast.makeText(PattenSetPwdActivity.this, "请重新绘制密码!", Toast.LENGTH_SHORT).show();

                        }
                    }
                }

            }
        });

    }
}

 

绘制密码界面布局复用上面的布局

 

 

public class PattenCheckPwdActivity extends AppCompatActivity {

    private SharedPreferences pre;
    private SharedPreferences.Editor edit;
    private PattenView patten_view_small;
    private TextView patten_username;
    private TextView patten_tip;
    private PattenView patten_view;
    private TextView patten_other;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_patten_check_pwd);
        pre = getSharedPreferences("data", MODE_PRIVATE);
        edit = pre.edit();

        initView();


    }

    private void initView() {
        patten_view_small = (PattenView) findViewById(R.id.patten_view_small);
        patten_username = (TextView) findViewById(R.id.patten_username);
        patten_tip = (TextView) findViewById(R.id.patten_tip);
        patten_view = (PattenView) findViewById(R.id.patten_view);
        patten_other = (TextView) findViewById(R.id.patten_other);

        patten_view.checkTrue(pre.getString("patten",""),new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 200) {
                    patten_tip.setTextColor(Color.GREEN);
                    patten_tip.setText("绘制密码成功");
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            startActivity(new Intent(PattenCheckPwdActivity.this, MainActivity.class));
                            finish();
                        }
                    }, 1000);
                } else {
                    patten_tip.setTextColor(Color.RED);
                    patten_tip.setText("密码错误");
                    TranslateAnimation translateAnimation = new TranslateAnimation(-20, 20, 0, 0);
                    translateAnimation.setRepeatCount(5);
                    translateAnimation.setDuration(1000);
                    patten_tip.setAnimation(translateAnimation);
                    Toast.makeText(PattenCheckPwdActivity.this, "请重新绘制密码!", Toast.LENGTH_SHORT).show();

                }
            }
        });

        patten_other.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(PattenCheckPwdActivity.this, LoginActivity.class));
                finish();
            }
        });
    }
}

 

大致代码就这些

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值