最近需要做图案解锁功能,所以自定义了下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();
}
});
}
}
大致代码就这些