好用的android九宫格密码锁代码实现。(前段时间博客被盗好久没写了。)

1,密码view控件:

package com.wansi.leadermanager.ui.layouts;


import java.util.ArrayList;
import java.util.List;


import junit.framework.Assert;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;


import com.wansi.leadermanager.R;
import com.wansi.leadermanager.model.bean.PasswordElement;
import com.wansi.leadermanager.utils.ConvertUtil;
/**
 * 
 * @author lchli
 *
 */
public class NineShapePasswordView extends View implements OnTouchListener {


public static interface InputPasswordCallback {


void onInputCorrect(String password);


void onInputWrong();


}


private InputPasswordCallback mSetPasswordCallback;
private int columnsCount;
private CharSequence[] pwdValues;


public void setCallback(InputPasswordCallback callback) {


mSetPasswordCallback = callback;
}


public NineShapePasswordView(Context context, int columns,
CharSequence[] values) {
super(context);
// TODO Auto-generated constructor stub
Assert.assertTrue("columns must>0", columns > 0);
Assert.assertTrue("values cannot be empty.", values != null
&& values.length > 0);
columnsCount = columns;
pwdValues = values;


setting();
}


public NineShapePasswordView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.passwordView);
columnsCount = a.getInt(
R.styleable.passwordView_passwordView_columnsCount, 3);
pwdValues = a
.getTextArray(R.styleable.passwordView_passwordView_pwdValues);
a.recycle();
Assert.assertTrue("columns must>0", columnsCount > 0);
Assert.assertTrue("values cannot be empty.", pwdValues != null
&& pwdValues.length > 0);
//
setting();
}


public NineShapePasswordView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.passwordView);
columnsCount = a.getInt(
R.styleable.passwordView_passwordView_columnsCount, 3);
pwdValues = a
.getTextArray(R.styleable.passwordView_passwordView_pwdValues);
a.recycle();
Assert.assertTrue("columns must>0", columnsCount > 0);
Assert.assertTrue("values cannot be empty.", pwdValues != null
&& pwdValues.length > 0);
//
setting();
}


private void setting() {
elements = new ArrayList<PasswordElement>(columnsCount);
elementsSeleted = new ArrayList<PasswordElement>(columnsCount);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.setOnTouchListener(this);
}


private List<PasswordElement> elements;
private List<PasswordElement> elementsSeleted;
private static final int ELEMENT_H_PADDING = 50;
private static final int ELEMENT_V_PADDING = 50;


private static final int INNER_R_STROKE_WIDTH = 2;
private static final int INNER_R_COLOR = Color.WHITE;


private static final int OUTER_R_STROKE_WIDTH = 5;
private static final int OUTER_R_NORMAL_COLOR = Color.TRANSPARENT;
private static final int OUTER_R_SELECTED_COLOR = Color.GREEN;
private static final int OUTER_R_ERROR_COLOR = Color.RED;


private static final int LINE_STROKE_WIDTH = 6;
private static final int LINE_COLOR = Color.GRAY;
private static final int LINE_ALP = 100;
private Paint mPaint = new Paint();
private Paint mLinePaint = new Paint();


private int dipToPix(float dip) {
return ConvertUtil.dip2px(getContext(), dip);


}


private void init(int w, int h) {


mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Style.STROKE);
//
mLinePaint.setAntiAlias(true);
mLinePaint.setDither(true);
mLinePaint.setStyle(Style.STROKE);
mLinePaint.setStrokeWidth(dipToPix(LINE_STROKE_WIDTH));
mLinePaint.setColor(LINE_COLOR);
mLinePaint.setAlpha(LINE_ALP);
//
int vPadding = dipToPix(ELEMENT_V_PADDING);
int hPadding = dipToPix(ELEMENT_H_PADDING);


int rowR = (w - (columnsCount + 1) * hPadding) / columnsCount / 2;
int elementSize = pwdValues.length;
int rows;
if (elementSize % columnsCount == 0)
rows = elementSize / columnsCount;
else
rows = elementSize / columnsCount + 1;


int colR = (h - (rows + 1) * vPadding) / rows / 2;


int outerR = rowR > colR ? colR : rowR;
//
int newWidth = columnsCount * 2 * outerR + (columnsCount + 1)
* hPadding;
int newHeight = rows * 2 * outerR + (rows + 1) * vPadding;
ViewGroup.LayoutParams lp = this.getLayoutParams();
lp.width = newWidth;
lp.height = newHeight;
this.setLayoutParams(lp);
//
int innerR = outerR / 4;
float defcx = hPadding + outerR;
float defcy = vPadding + outerR;
float cx = defcx;
float cy = defcy;
float innerRstrokeWidth = dipToPix(INNER_R_STROKE_WIDTH);
float outerRstrokeWidth = dipToPix(OUTER_R_STROKE_WIDTH);


PasswordElement tmp;
for (int i = 0; i < elementSize; i++) {
tmp = new PasswordElement();


tmp.setCx(cx);
tmp.setCy(cy);
tmp.setInnerR(innerR);
tmp.setOuterR(outerR);
tmp.setInnerRStrokeWidth(innerRstrokeWidth);
tmp.setOuterRStrokeWidth(outerRstrokeWidth);
tmp.setInnerRColor(INNER_R_COLOR);
tmp.setState(PasswordElement.STATE_NORMAL);
tmp.setValue(pwdValues[i].toString());
tmp.setOuterRNormalColor(OUTER_R_NORMAL_COLOR);
tmp.setOuterRSelectedColor(OUTER_R_SELECTED_COLOR);
tmp.setOuterRErrorColor(OUTER_R_ERROR_COLOR);
elements.add(tmp);
// change location.
if ((i + 1) % columnsCount == 0) {
cx = defcx;
cy = cy + vPadding + 2 * outerR;
} else {
cx = cx + hPadding + outerR * 2;
// cy not changed.
}
}


}


private boolean isInited = false;


@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub


super.onLayout(changed, left, top, right, bottom);
if (!isInited) {
init(this.getWidth(), this.getHeight());
isInited = true;
}


}


@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
if (elements.isEmpty())
return;
for (PasswordElement ele : elements) {// draw circles.
mPaint.setColor(ele.getInnerRColor());
mPaint.setStrokeWidth(ele.getInnerRStrokeWidth());
/*
* draw inner circle.
*/
canvas.drawCircle(ele.getCx(), ele.getCy(), ele.getInnerR(), mPaint);


mPaint.setStrokeWidth(ele.getOuterRStrokeWidth());
mPaint.setColor(ele.getCurrentOuterRcolor());
/*
* draw outer circle.
*/
canvas.drawCircle(ele.getCx(), ele.getCy(), ele.getOuterR(), mPaint);// draw


}// for end.
//


if (!elementsSeleted.isEmpty()) {// draw lines.


for (int i = 0; i < elementsSeleted.size() - 1; i++) {
PasswordElement e = elementsSeleted.get(i);
canvas.drawLine(e.getCx(), e.getCy(), elementsSeleted
.get(i + 1).getCx(),
elementsSeleted.get(i + 1).getCy(), mLinePaint);
}
if (lastMoveX != -1) {
PasswordElement e = elementsSeleted
.get(elementsSeleted.size() - 1);


canvas.drawLine(e.getCx(), e.getCy(), lastMoveX, lastMoveY,
mLinePaint);
}
}
//
super.onDraw(canvas);


}


private void checkFocusedElement(float x, float y) {
for (PasswordElement ele : elements) {
if (isTouchPointInElement(x, y, ele)) {


if (!elementsSeleted.contains(ele)) {// avoid repeat.
ele.setState(PasswordElement.STATE_SELECTED);
elementsSeleted.add(ele);
}
return;
}


}


}


private static boolean isTouchPointInElement(float x, float y,
PasswordElement ele) {
double d = Math.pow((x - ele.getCx()), 2)
+ Math.pow((y - ele.getCy()), 2);
d = Math.sqrt(d);


return d <= ele.getOuterR();


}


private float lastMoveX = -1;
private float lastMoveY = -1;


@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub


float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:


resetAllElements();
checkFocusedElement(x, y);
lastMoveX = -1;
lastMoveY = -1;


invalidate();
break;
case MotionEvent.ACTION_MOVE:
checkFocusedElement(x, y);
lastMoveX = x;
lastMoveY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
// checkFocusedElement(x, y);
boolean isRight = checkSelectedElement();
lastMoveX = -1;
lastMoveY = -1;
invalidate();
//
if (mSetPasswordCallback != null) {
if (isRight)
mSetPasswordCallback.onInputCorrect(getInputPwd());
else
mSetPasswordCallback.onInputWrong();


}
break;


}
return true;
}


private String getInputPwd() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < elementsSeleted.size(); i++) {
sb.append(elementsSeleted.get(i).getValue());
}


return sb.toString();
}


private void resetAllElements() {
elementsSeleted.clear();
for (PasswordElement e : elements) {
e.setState(PasswordElement.STATE_NORMAL);
}


}


private static final int MIN_REQUIRED_PWD_COUNTS = 4;


private boolean checkSelectedElement() {
if (elementsSeleted.size() < MIN_REQUIRED_PWD_COUNTS) {
for (PasswordElement e : elementsSeleted) {
e.setState(PasswordElement.STATE_ERROR);


}
return false;
} else {
return true;
}


}


}

2,密码item数据模型:

package com.wansi.leadermanager.model.bean;


/**
 * 
 * @author lchli
 * 
 */
public class PasswordElement {


public static final int STATE_NORMAL = 1;
public static final int STATE_SELECTED = 2;
public static final int STATE_ERROR = 3;


private float cx;
private float cy;


private float innerR;
private int innerRColor;
private float innerRStrokeWidth;


private float outerR;
private float outerRStrokeWidth;
private int outerRNormalColor;
private int outerRSelectedColor;
private int outerRErrorColor;


private int state = STATE_NORMAL;
private String value;


public int getCurrentOuterRcolor() {
switch (state) {
case PasswordElement.STATE_NORMAL:
return outerRNormalColor;
case PasswordElement.STATE_SELECTED:
return outerRSelectedColor;
case PasswordElement.STATE_ERROR:
return outerRErrorColor;
default:
return outerRNormalColor;


}


}


public float getCx() {
return cx;
}


public void setCx(float cx) {
this.cx = cx;
}


public float getCy() {
return cy;
}


public void setCy(float cy) {
this.cy = cy;
}


public float getInnerR() {
return innerR;
}


public void setInnerR(float innerR) {
this.innerR = innerR;
}


public int getInnerRColor() {
return innerRColor;
}


public void setInnerRColor(int innerRColor) {
this.innerRColor = innerRColor;
}


public float getInnerRStrokeWidth() {
return innerRStrokeWidth;
}


public void setInnerRStrokeWidth(float innerRStrokeWidth) {
this.innerRStrokeWidth = innerRStrokeWidth;
}


public float getOuterR() {
return outerR;
}


public void setOuterR(float outerR) {
this.outerR = outerR;
}


public float getOuterRStrokeWidth() {
return outerRStrokeWidth;
}


public void setOuterRStrokeWidth(float outerRStrokeWidth) {
this.outerRStrokeWidth = outerRStrokeWidth;
}


public int getOuterRNormalColor() {
return outerRNormalColor;
}


public void setOuterRNormalColor(int outerRNormalColor) {
this.outerRNormalColor = outerRNormalColor;
}


public int getOuterRSelectedColor() {
return outerRSelectedColor;
}


public void setOuterRSelectedColor(int outerRSelectedColor) {
this.outerRSelectedColor = outerRSelectedColor;
}


public int getOuterRErrorColor() {
return outerRErrorColor;
}


public void setOuterRErrorColor(int outerRErrorColor) {
this.outerRErrorColor = outerRErrorColor;
}


public int getState() {
return state;
}


public void setState(int state) {
this.state = state;
}


public String getValue() {
return value;
}


public void setValue(String value) {
this.value = value;
}


}


3,密码属性attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <declare-styleable name="passwordView">
         <!-- 密码列数 -->
        <attr name="passwordView_columnsCount" format="integer"/>
         <!-- 密码值集合数组,如0123456789 -->
        <attr name="passwordView_pwdValues" format="reference"/>
    </declare-styleable> 
</resources>


4,测试activity:

package com.wansi.leadermanager.ui.activities;


import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;


import com.wansi.leadermanager.R;
import com.wansi.leadermanager.ui.layouts.NineShapePasswordView;
import com.wansi.leadermanager.ui.layouts.NineShapePasswordView.InputPasswordCallback;


public class LoginActivity extends Activity implements InputPasswordCallback {


private NineShapePasswordView pwdView;
private TextView tvInfo;




@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pwdView = (NineShapePasswordView) findViewById(R.id.pwdView);
pwdView.setCallback(this);
tvInfo = (TextView) findViewById(R.id.tvInfo);
}


@Override
public void onInputCorrect(String password) {
// TODO Auto-generated method stub
if (validatePwdInDb(password)) {
tvInfo.setText("success pwd:" + password);
// todo start mainactivity.
} else {
tvInfo.setText("pwd error.,please retry");
}


}


private static boolean validatePwdInDb(String password) {
return true;


}


@Override
public void onInputWrong() {
// TODO Auto-generated method stub
tvInfo.setText("format error,please retry");
}


}


5,main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <com.wansi.leadermanager.ui.layouts.NineShapePasswordView
        xmlns:leadermanager="http://schemas.android.com/apk/res/com.wansi.leadermanager"
        android:id="@+id/pwdView"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:background="@android:color/transparent"
        leadermanager:passwordView_columnsCount="3"
        leadermanager:passwordView_pwdValues="@array/pwdValues" />




    <TextView
        android:id="@+id/tvInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView" />


</LinearLayout>


6,strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>


    <string name="app_name">LeaderManager</string>
    <string name="hello">Hello World!</string>


    <string-array name="pwdValues">
        <item>0</item>
        <item>1</item>
        <item>2</item>
        <item>3</item>
        <item>4</item>
        <item>5</item>
        <item>6</item>
        <item>7</item>
        <item>8</item>
         
    </string-array>


</resources>


==================================end============================================



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值