自定义控件实现锁屏效果!

     现在很多app多具有滑动解锁的功能!多以就是这自己写了一个,先来看一下效果图

具体实现是先自定义了一个GestureLockView继承View,即我用看到的圆圈;在自定义一个GestureLockViewLayout继承RelativeLayout用于存放我们自定义的GestureLockView

下面是自定义GestureLockView的代码:

package com.wang.gesturelockview.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path.FillType;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;

public class GestureLockView extends View {
	/**
	 * GestureLockView的三种状态
	 */
	enum Mode {
		STATUS_NO_FINGER, STATUS_FINGER_ON, STATUS_FINGER_UP;
	}

	/**
	 * 当前的状态
	 */
	private Mode mCurrentStatus = Mode.STATUS_NO_FINGER;

	/**
	 * 三种状态下不同的颜色
	 */
	private int color_No_finger = Color.WHITE;
	private int color_finger_on = Color.GREEN;
	private int color_finger_up = Color.RED;

	/**
	 * 圆心坐标和半径
	 */
	private float centerX;
	private float centerY;
	private float radius;
	// 内圆的半径和外圆的半径的比值
	private float innerCircleRate = 0.333f;

	/**
	 * 三角形小箭头
	 */
	private float mArrowRate = 0.333f;// 缩小的比例
	private int mArrowDegree = -1;// 偏转度数,初始向上
	private Path mArrowPath;

	/**
	 * 画笔 线条的宽度
	 */
	private Paint mPaint;
	private int mStrokeWidth = 2;
	private int mWidth;

	public GestureLockView(Context context) {
		this(context, null, 0);
	}

	public GestureLockView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public GestureLockView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int width = MeasureSpec.getSize(widthMeasureSpec);
		int height = MeasureSpec.getSize(heightMeasureSpec);

		mWidth = width < height ? width : height;
		centerX = centerY = radius = mWidth / 2;
		radius = radius - mStrokeWidth / 2;

		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		// 画三角形
		mArrowPath = new Path();
		float arrowWidth = mWidth * mArrowRate / 3;
		mArrowPath.moveTo(mWidth * 1.0f / 2, mWidth * 1.0f / 9);
		mArrowPath.lineTo(mWidth / 2 - arrowWidth / 2, mWidth * 2.0f / 9);
		mArrowPath.lineTo(mWidth / 2 + arrowWidth / 2, mWidth * 2.0f / 9);
		mArrowPath.close();// 会自动加上首尾线
		mArrowPath.setFillType(FillType.WINDING);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		if (mCurrentStatus == Mode.STATUS_NO_FINGER) {
			mPaint.setStyle(Style.STROKE);
			mPaint.setStrokeWidth(mStrokeWidth);
			mPaint.setColor(color_No_finger);
			canvas.drawCircle(centerX, centerY, radius, mPaint);

		} else if (mCurrentStatus == Mode.STATUS_FINGER_ON) {
			mPaint.setStyle(Style.STROKE);
			mPaint.setStrokeWidth(mStrokeWidth);
			mPaint.setColor(color_finger_on);
			canvas.drawCircle(centerX, centerY, radius, mPaint);

			mPaint.setStyle(Style.FILL);
			canvas.drawCircle(centerX, centerY, radius * innerCircleRate,
					mPaint);

		} else if (mCurrentStatus == Mode.STATUS_FINGER_UP) {
			mPaint.setStyle(Style.STROKE);
			mPaint.setStrokeWidth(mStrokeWidth);
			mPaint.setColor(color_finger_up);
			canvas.drawCircle(centerX, centerY, radius, mPaint);

			mPaint.setStyle(Style.FILL);
			canvas.drawCircle(centerX, centerY, radius * innerCircleRate,
					mPaint);
			
			//画箭头
			if(mArrowDegree!=-1){
				canvas.save();//保存原先
				canvas.rotate(mArrowDegree, centerX, centerY);
				canvas.drawPath(mArrowPath, mPaint);
				canvas.restore();
			}
		}

		super.onDraw(canvas);
	}
	
	public void setDegree(int mArrowDegree){
		this.mArrowDegree=mArrowDegree;
	}
	
	public int getDegree(){
		return mArrowDegree;
	}
	
	public void setMode(Mode mode){
		this.mCurrentStatus=mode;
		invalidate();
	}
}

下面是 GestureLockViewLayout的代码:

package com.wang.gesturelockview.view;

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

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.wang.gesturelockview.view.GestureLockView.Mode;

public class GestureLockViewLayout extends RelativeLayout {
	/**
	 * 保存GestureLockView的数组
	 */
	private GestureLockView[] gestureLockViews;
	/**
	 * 每个边上GestureLockView的个数
	 */
	private int mCount = 3;
	/**
	 * 存储的答案
	 */
	private int[] answer={1,2,3};
	/**
	 * 保存用户已选gestureLockView的id
	 */
	private List<Integer> choose = new ArrayList<Integer>();

	/**
	 * 两个GestureLockView之间的距离
	 */
	private int mMarginBetweenLockView = 30;
	/**
	 * GestureLockView的边长
	 */
	private int mGestureLockViewWidth = (int) TypedValue
			.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources()
					.getDisplayMetrics());

	private int color;// 待会补充
	/**
	 * 控件的高宽
	 */
	private int mWidth;
	private int mHeight;
	/**
	 * 画宽线的画笔
	 */
	private Paint mPaint;
	/**
	 * 指引线对象
	 */
	private Path mPath;
	/**
	 * 指引线开始的坐标
	 */
	private int mLastPathX = 0;
	private int mLastPahtY = 0;
	/**
	 * 指引线结束的位置
	 */
	private PointF mTmpTarget = new PointF();

	/**
	 * 最大尝试次数
	 */
	private int mTryTimes = 5;

	public GestureLockViewLayout(Context context) {
		this(context, null, 0);
	}

	public GestureLockViewLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public GestureLockViewLayout(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);

		// 初始化画笔对象,线对象
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaint.setStyle(Style.STROKE);
		mPaint.setStrokeCap(Cap.ROUND);
		mPaint.setStrokeJoin(Join.ROUND);

		mPath = new Path();
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		mWidth = MeasureSpec.getSize(widthMeasureSpec);
		mHeight = MeasureSpec.getSize(heightMeasureSpec);

		mWidth = mHeight = mWidth < mHeight ? mWidth : mHeight;
		// 初始化所有的GestureLockView
		if (gestureLockViews == null) {
			gestureLockViews = new GestureLockView[mCount * mCount];

			mMarginBetweenLockView = (mWidth - mGestureLockViewWidth * mCount)
					/ (mCount + 2);

			// 初始化画笔的宽度
			mPaint.setStrokeWidth(0.34f * mGestureLockViewWidth);
			mPaint.setColor(Color.GREEN);
			mPaint.setAlpha(50);

			for (int i = 0; i < gestureLockViews.length; i++) {

				Log.i("wangsongbin", i + "");
				// 生成子view,并赋予其id;
				gestureLockViews[i] = new GestureLockView(getContext());
				gestureLockViews[i].setId(i + 1);
				LayoutParams lp = new LayoutParams(mGestureLockViewWidth,
						mGestureLockViewWidth);
				if (i % mCount != 0) {// 不是第一例的
					lp.addRule(RelativeLayout.RIGHT_OF,
							gestureLockViews[i - 1].getId());
				}
				if (i >= mCount) {// 不是第一行
					lp.addRule(RelativeLayout.BELOW, gestureLockViews[i
							- mCount].getId());
				}
				// 设置左右上下的边距
				float rightMargin = 0;
				float leftMargin;
				float topMargin;
				float bottomMargin = 0;
				if (i % mCount == 0) {// 第一例
					leftMargin = (float) (1.5 * mMarginBetweenLockView);
				} else {
					leftMargin = mMarginBetweenLockView;
				}

				if (i < mCount) {// 第一行
					topMargin = (float) (1.5 * mMarginBetweenLockView);
				} else {
					topMargin = mMarginBetweenLockView;
				}

				lp.setMargins((int) leftMargin, (int) topMargin,
						(int) rightMargin, (int) bottomMargin);
				gestureLockViews[i].setMode(Mode.STATUS_NO_FINGER);
				addView(gestureLockViews[i], lp);
			}
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		float x = event.getX();
		float y = event.getY();
		Log.i("wangsongbin", "x:" + x + " y:" + y);

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// 把所有的GestureLockView初始化为status_no_finger
			resetGestureLockView();
			break;
		case MotionEvent.ACTION_MOVE:
			// 改变连接线的颜色
			mPaint.setColor(Color.GREEN);
			mPaint.setAlpha(50);
						
			GestureLockView child = getChildByPoint(x, y);
			if (child != null) {
				if (!choose.contains(child.getId())) {
					choose.add(child.getId());
					child.setMode(Mode.STATUS_FINGER_ON);
					mLastPathX = (child.getLeft() + child.getRight()) / 2;
					mLastPahtY = (child.getTop() + child.getBottom()) / 2;
					if (choose.size() == 1) {
						mPath.moveTo(mLastPathX, mLastPahtY);
					} else {
						mPath.lineTo(mLastPathX, mLastPahtY);
					}
				}
			}
			mTmpTarget.x = x;
			mTmpTarget.y = y;
			break;
		case MotionEvent.ACTION_UP:
			
			// 减少输入密码的次数
			mTryTimes--;
			// 将超出的点设置成最后的端点上
			mTmpTarget.x = mLastPathX;
			mTmpTarget.y = mLastPahtY;
			//校对答案
			if(checkAnswer()){
				Toast.makeText(getContext(), "密码正确", Toast.LENGTH_LONG).show();
				break;
			}
			
			// 改变连接线的颜色
			mPaint.setColor(Color.RED);
			mPaint.setAlpha(50);
			
			// 计算偏转的角度
			changeChoosedItem();
			for (int i = 0; i < choose.size() - 1; i++) {
				int childId = choose.get(i);
				int nextChildId = choose.get(i + 1);
				GestureLockView startChild = (GestureLockView) GestureLockViewLayout.this
						.findViewById(childId);
				GestureLockView nextChild = (GestureLockView) GestureLockViewLayout.this
						.findViewById(nextChildId);
				int dx=nextChild.getLeft()-startChild.getLeft();
				int dy=nextChild.getTop()-startChild.getTop();
				//计算角度
				int degree=(int) Math.toDegrees(Math.atan2(dy, dx))+90;
                startChild.setDegree(degree);
			}
           

			break;
		}
		invalidate();// 父容器的重新初始化,会带动,子控件的重新初始化
		return true;
	}

	private boolean checkAnswer() {
		if(answer.length!=choose.size()){
			return false;
		}
		for(int i=0;i<answer.length;i++){
			if(answer[i]!=choose.get(i)){
				return false;
			}
		}
		return true;
	}

	private void changeChoosedItem() {
		for (int i = 0; i < choose.size(); i++) {
			GestureLockView view = (GestureLockView) this.findViewById(choose
					.get(i));
			view.setDegree(-1);
			view.setMode(Mode.STATUS_FINGER_UP);
		}
	}

	/**
	 * 重新初始化所有的GestureLockView
	 */
	private void resetGestureLockView() {
		choose.clear();
		mPath.reset();
		for (int i = 0; i < gestureLockViews.length; i++) {
			gestureLockViews[i].setMode(Mode.STATUS_NO_FINGER);
		}

	}

	/**
	 * 根据触点坐标判断它出发了那个圆圈
	 * 
	 * @param x
	 * @param y
	 * @return
	 */
	private GestureLockView getChildByPoint(float x, float y) {

		for (int i = 0; i < gestureLockViews.length; i++) {
			GestureLockView view = gestureLockViews[i];
			// 设置一个内边距
			float padding = 0.15f * mGestureLockViewWidth;
			if (x > (view.getLeft() + padding)
					&& x < (view.getRight() + padding)
					&& y > (view.getTop() + padding)
					&& y < (view.getBottom() - padding)) {
				return view;
			}
		}
		return null;
	};

	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
		if (mPath != null) {
			canvas.drawPath(mPath, mPaint);
		}
		// 绘制引线
		if (mLastPathX != 0 && mLastPahtY != 0) {
			canvas.drawLine(mLastPathX, mLastPahtY, mTmpTarget.x, mTmpTarget.y,
					mPaint);
		}
	}

}
下面附上源代码:


源代码下载










    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值