前一久写了一个图形锁的view,实现的难度不是很大,不过对初学者学习自定义view,觉得还是一个很好的例子吧,当然每个人实现的图形锁界面有不同的逻辑,对界面之间的连接也有不一样的控制能力。如果本文有功能没有达到读者的需求或者是与读者需求不一样的,可以自己改一下代码,都很简单
先上图片
![没有划线的时候]
![匹配错误的时候]
代码
##点的类,在里面实现draw方法。##
/**
* Created by sunshine
*/
public class Point {
//私有属性
private int id;
private float x;
private float y;
private boolean isTouched;
private boolean isError;
private Paint paint;
/**
* 共有属性
*/
//圆环的画笔大小
private static int STROKE_WIDTH=10;
//普通颜色
private static int COLOR_DEFAULT= Color.YELLOW;
//点击之后的颜色
private static int COLOR_CHOOSED=Color.GREEN;
//错误之后的颜色
private static int COLOR_ERROR=Color.RED;
//圆环的半径
private float radious;
public Point(){}
public Point(float x,float y,int id){
this.x=x;
this.y=y;
this.isError=false;
this.isTouched=false;
radious=60;
paint=new Paint();
this.id=id;
}
public void setTouched(boolean isTouched){
this.isTouched=isTouched;
}
public void setIsError(boolean isError){
this.isError=isError;
}
public void draw(Canvas canvas){
paint.setColor(isTouched ? (isError ? COLOR_ERROR : COLOR_CHOOSED) : COLOR_DEFAULT);
paint.setStrokeWidth(STROKE_WIDTH);
paint.setAntiAlias(true);
canvas.drawPoint(x, y, paint);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(x,y,radious,paint);
}
public static void setColorChoosed(int colorChoosed) {
COLOR_CHOOSED = colorChoosed;
}
public static void setColorDefault(int colorDefault) {
COLOR_DEFAULT = colorDefault;
}
public static void setColorError(int colorError) {
COLOR_ERROR = colorError;
}
public static void setStrokeWidth(int strokeWidth) {
STROKE_WIDTH = strokeWidth;
}
public void setRadious(float radious) {
this.radious = radious;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
public void setIsTouched(boolean isTouched) {
this.isTouched = isTouched;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public int getId() {
return id;
}
public boolean getTouchState(){
return isTouched;
}
public void setLocation(float x, float y) {
this.x=x;
this.y=y;
}
}
接下来就是主要的ImageLock的view了
首先我们的ImageLock 要继承自View 然后重写onlayout 方法,在onlayout方法中进行布局。将9个点的分布处理好
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
height=getHeight();
width=getWidth();
pointList.clear();
//进行点的布局
for(int i=0;i<3;i++){
for (int j=0;j<3;j++){
Point point=new Point((2*j+1)*width/6,(2*i+1)*width/6,i*3+j);
pointList.add(point);
}
}
}
然后就是画点划线了,在这里我们定义一个划线的方法,然后监视手指触摸的那个点跟九个点的距离,这个距离在小于预先设定的一个值的时候就判定那个点被选中
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画一般的点
for(int i=0;i<pointList.size();i++){
Point point=pointList.get(i);
point.draw(canvas);
}
//划线
if(pointQueue.size()>0){
drawTouchedLine(canvas);
}
}
public void drawTouchedLine(Canvas canvas){
//设置画笔的粗细
linePaint.setStrokeWidth(painWidth);
//设置画笔的颜色
if(isMatch){
linePaint.setColor(matchColor);
}else{
linePaint.setColor(errorColor);
}
//设置画笔的透明度
linePaint.setAlpha(100);
for(int j=0;j<pointQueue.size()-1;j++){
Point point1=pointQueue.get(j);
Point point2=pointQueue.get(j+1);
canvas.drawLine(point1.getX(),point1.getY(),point2.getX(),point2.getY(),linePaint);
}
//最后一条能动的线
if(isMatch&&isTouched){
Point latePoint=pointQueue.get(pointQueue.size()-1);
canvas.drawLine(latePoint.getX(),latePoint.getY(),eventPoint.getX(),eventPoint.getY(),linePaint);
}else{
return ;
}
}
最后将视图的手势抬起设置一个接口
private OnTouchUpListener listener;
public interface OnTouchUpListener{
public void onTouchUp();
}
public void setTouchUpListener(OnTouchUpListener listener){
this.listener=listener;
}
这里将所有的代码贴出来吧,不难,也没有什么写的
public class ImageLock extends View {
//视图的整体宽高
private int height;
private int width;
/**
* 存放所有点的集合
*/
private List<Point> pointList=new ArrayList<Point>();
/**
*被选择点的顺序队列
*/
private List<Point> pointQueue=new ArrayList<Point>();
/**
* 是否是对的
*/
private boolean isMatch;
/**
* 事件的点
*/
private Point eventPoint;
/**
* 圆的半径
*/
private int radious;
/**
* 画线的画笔
*/
private Paint linePaint;
/**
* 划线的颜色
*/
private int matchColor;
private int errorColor;
/**
* 划线的粗细
*/
private int painWidth;
/**
* 是否抬起来
*/
private boolean isTouched;
private OnTouchUpListener listener;
public interface OnTouchUpListener{
public void onTouchUp();
}
public ImageLock(Context context) {
super(context);
init();
}
public ImageLock(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ImageLock(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void init(){
isMatch=true;
radious=50;
linePaint=new Paint();
eventPoint=new Point();
matchColor=Color.CYAN;
errorColor=Color.RED;
painWidth=20;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
height=getHeight();
width=getWidth();
pointList.clear();
//进行点的布局
for(int i=0;i<3;i++){
for (int j=0;j<3;j++){
Point point=new Point((2*j+1)*width/6,(2*i+1)*width/6,i*3+j);
pointList.add(point);
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画一般的点
for(int i=0;i<pointList.size();i++){
Point point=pointList.get(i);
point.draw(canvas);
}
//划线
if(pointQueue.size()>0){
drawTouchedLine(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
eventPoint.setLocation(event.getX(), event.getY());
isTouched=true;
//判断是不是触碰到点
pointTouchEvent(eventPoint);
break;
case MotionEvent.ACTION_UP:
isTouched=false;
if(listener!=null){
listener.onTouchUp();
}
invalidate();
break;
}
return true;
}
public void drawTouchedLine(Canvas canvas){
//设置画笔的粗细
linePaint.setStrokeWidth(painWidth);
//设置画笔的颜色
if(isMatch){
linePaint.setColor(matchColor);
}else{
linePaint.setColor(errorColor);
}
//设置画笔的透明度
linePaint.setAlpha(100);
for(int j=0;j<pointQueue.size()-1;j++){
Point point1=pointQueue.get(j);
Point point2=pointQueue.get(j+1);
canvas.drawLine(point1.getX(),point1.getY(),point2.getX(),point2.getY(),linePaint);
}
//最后一条能动的线
if(isMatch&&isTouched){
Point latePoint=pointQueue.get(pointQueue.size()-1);
canvas.drawLine(latePoint.getX(),latePoint.getY(),eventPoint.getX(),eventPoint.getY(),linePaint);
}else{
return ;
}
}
public void pointTouchEvent(Point point){
for(int i=0;i<pointList.size();i++){
Point currenPoint=pointList.get(i);
//判断是否触碰到点
if(Math.sqrt(Math.pow(point.getX()-currenPoint.getX(),2)+Math.pow(point.getY()-currenPoint.getY(),2))<=radious){
//给触碰到的点进行压栈
for(int j=0;j<pointQueue.size();j++){
if(pointQueue.get(j).getId()==currenPoint.getId()){
return;//如果这个点已经在这个队列中就不让他可以压栈,从而进行事件的消费
}
}
pointList.get(i).setTouched(true);
currenPoint.setTouched(true);
pointQueue.add(currenPoint);
}
}
invalidate();
}
public void setMatch(boolean isMatch){
this.isMatch=isMatch;
for(int i=0;i<pointQueue.size();i++){
pointQueue.get(i).setIsError(!isMatch);
}
invalidate();
}
public void resetChooseList(){
pointQueue.clear();
for(int i=0;i<pointList.size();i++){
pointList.get(i).setTouched(false);
pointList.get(i).setIsError(false);
}
isMatch=true;
invalidate();
}
public String getSecret(){
String secret=new String();
for(int i=0;i<pointQueue.size();i++){
secret+=pointQueue.get(i).getId();
}
return secret;
}
public void setTouchUpListener(OnTouchUpListener listener){
this.listener=listener;
}
public void setErrorColor(int errorColor) {
this.errorColor = errorColor;
}
public void setLinePaint(Paint linePaint) {
this.linePaint = linePaint;
}
public void setMatchColor(int matchColor) {
this.matchColor = matchColor;
}
public void setPainWidth(int painWidth) {
this.painWidth = painWidth;
}
public void setRadious(int radious) {
this.radious = radious;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
}
最后在主函数中调用
具体怎么设置视图都有接口,还可以对数据进行一些加密保存在本地,具体也就不在阐述了,一下是我测试的时候的代码以及布局文件
public class MainActivity extends AppCompatActivity {
private ImageLock imageLock;
private Button btn;
String str;
private String key="123";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageLock= (ImageLock) findViewById(R.id.iamgeLock_main);
btn= (Button) findViewById(R.id.btn_main_clear);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageLock.resetChooseList();
}
});
imageLock.setTouchUpListener(new ImageLock.OnTouchUpListener() {
@Override
public void onTouchUp() {
imageLock.setMatch(false);
str = imageLock.getSecret();
if(str.equals(key)){
Toast.makeText(MainActivity.this,"right",Toast.LENGTH_SHORT).show();
imageLock.setMatch(true);
}else{
imageLock.setMatch(false);
}
}
});
}
}
布局文件
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".activity.MainActivity">
<com.happysmile.imagelock.custom.ImageLock
android:layout_marginBottom="150dp"
android:id="@+id/iamgeLock_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_alignParentBottom="true"
android:layout_width="wrap_content"
android:layout_height="150dp">
<Button
android:background="@color/colorPrimary"
android:textSize="50dp"
android:gravity="center"
android:layout_alignParentBottom="true"
android:text="clear"
android:id="@+id/btn_main_clear"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
最后:本人写博客经验不足,水平有限,还望大家多指正,共同学习
871



被折叠的 条评论
为什么被折叠?



