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

来源:互联网 发布:网易云课堂mac版 编辑:程序博客网 时间:2024/06/16 11:24

     现在很多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);}@Overrideprotected 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);}@Overrideprotected 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();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight = MeasureSpec.getSize(heightMeasureSpec);mWidth = mHeight = mWidth < mHeight ? mWidth : mHeight;// 初始化所有的GestureLockViewif (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);}}}@Overridepublic 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_fingerresetGestureLockView();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;};@Overrideprotected 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
原创粉丝点击