天天看點

自定義控件實作鎖屏效果!

     現在很多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);
		}
	}

}
           

下面附上源代碼:

源代碼下載下傳