自定义宫格锁
2016-06-14 18:10
260 查看
传承者(Inheritors)打造共同进步生态圈!!!
转载:http://blog.csdn.net/lmj623565791/article/details/36236113
三段论:自定义换图圆圈,再定义组合图九宫格,调用!
转载:http://blog.csdn.net/lmj623565791/article/details/36236113
先上图
三段论:自定义换图圆圈,再定义组合图九宫格,调用!
首先属性部分
文件attrs.xml<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="color_no_finger_inner_circle" format="color"/> <attr name="color_no_finger_outer_circle" format="color"/> <attr name="color_finger_on" format="color"/> <attr name="color_finger_up" format="color"/> <attr name="count" format="integer"/> <attr name="tryTimes" format="integer"/> <declare-styleable name="GestureLockViewGroup"> <attr name="color_no_finger_inner_circle"/> <attr name="color_no_finger_outer_circle"/> <attr name="color_finger_on"/> <attr name="color_finger_up"/> <attr name="count"/> <attr name="tryTimes"/> </declare-styleable> </resources>
自定义View
public class GestureLockView extends View { /** * GestureLockView的三种状态 */ enum Mode{ STATUS_NO_FINGER,STATUS_FINGER_ON,STATUS_FINGER_UP; } /** * GestureLockView的当前状态 */ private Mode mCurrentStatus = Mode.STATUS_NO_FINGER; //宽度,高度,外圆半径 private int mWidth,mHeight,mRadius; //画笔的宽度 private int mStrokeWidth = 2; //圆心左边 private int mCenterX,mCenterY; private Paint mPaint; //箭头(小三角最长的一半长度 = mArrawRate*mWidth/2) private float mArrowRate = 0.333f; private int mArrowDegree = -1; private Path mArrowPath; //内园的半径 = mInnerCircleRadiuRate * mRadus; private float mInnerCircleRadiusRate = 0.3f; //四种颜色,可由用户自定义,初始化时由GEstureLockViewGoup传入 private int mColorNoFingerInner,mColorNoFingerOutter,mColorFingerOn,mColorFingerUp; public GestureLockView(Context context, int mColorNoFingerOutter, int mColorNoFingerInner, int mColorFingerOn, int mColorFingerUp) { super(context); this.mColorNoFingerOutter = mColorNoFingerOutter; this.mColorNoFingerInner = mColorNoFingerInner; this.mColorFingerOn = mColorFingerOn; this.mColorFingerUp = mColorFingerUp; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mArrowPath = new Path(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = MeasureSpec.getSize(heightMeasureSpec); //取长和宽中的小值 mWidth = mWidth<mHeight ? mWidth:mHeight; mRadius = mCenterX = mCenterY = mWidth / 2; mRadius -= mStrokeWidth/2; //绘制三角形,初始时是个默认箭头朝上的一个等腰三角形,用户绘制结束后,根据两个GestureLockView决定需要旋转多少度 float mArrowLength = mWidth/2 * mArrowRate; mArrowPath.moveTo(mWidth/2,mStrokeWidth + 2); mArrowPath.lineTo(mWidth/2 - mArrowLength,mStrokeWidth + 2+ mArrowLength); mArrowPath.lineTo(mWidth/2+mArrowLength,mStrokeWidth+2 + mArrowLength); mArrowPath.close(); mArrowPath.setFillType(Path.FillType.WINDING); } @Override protected void onDraw(Canvas canvas) { switch (mCurrentStatus){ case STATUS_FINGER_ON: //绘制外圆 mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mColorFingerOn); mPaint.setStrokeWidth(2); canvas.drawCircle(mCenterX,mCenterY,mRadius,mPaint); //绘制内园 mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(mCenterX,mCenterY,mRadius*mInnerCircleRadiusRate,mPaint); break; case STATUS_FINGER_UP: //绘制外圆 mPaint.setColor(mColorFingerUp); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(2); canvas.drawCircle(mCenterX,mCenterY,mRadius,mPaint); //绘制内园 mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(mCenterX,mCenterY,mRadius*mInnerCircleRadiusRate,mPaint); drawArrow(canvas); break; case STATUS_NO_FINGER: //绘制外圆 mPaint.setColor(mColorNoFingerOutter); mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(mCenterX,mCenterY,mRadius,mPaint); //绘制内园 mPaint.setColor(mColorNoFingerInner); canvas.drawCircle(mCenterX,mCenterY,mRadius*mInnerCircleRadiusRate,mPaint); break; } } /** * 绘制箭头 * @param canvas */ private void drawArrow(Canvas canvas) { if(mArrowDegree != -1){ mPaint.setStyle(Paint.Style.FILL); canvas.save(); canvas.rotate(mArrowDegree,mCenterX,mCenterY); canvas.drawPath(mArrowPath,mPaint); canvas.restore(); } } public void setMode(Mode mode){ this.mCurrentStatus = mode; invalidate(); } public void setArrowDegree(int degree){ this.mArrowDegree = degree; } public int getmArrowDegree(){ return this.mArrowDegree; } }
自定义ViewGoup
public class GestureLockViewGoup extends RelativeLayout { //保存所有的GestureLockView private GestureLockView[] mGestureLockViews; //每个边上的GestureLockView的个数 private int mCount = 4; //存储答案 private int [] mAnswer = {0,1,2,5,8}; //保存用户选中的GestureLockView的id private List<Integer> mChose = new ArrayList<>(); private Paint mPaint; //每个GestureLockView中间的间距 设置为 mGestureLockViewWidth*25% private int mMaginBetweenLockView = 30; //GestureLockView的边长4*mWide/(5*mCount + 1) private int mGestureLockViewWidth; //GestureLockView无手指触摸的状态下内圆的颜色 private int mNoFingerInnerCircleColor = 0xFF939090; //GestureLockView无手指触摸状态下的外圆的颜色 private int mNoFingerOuterCircleColor = 0xFFE0DBDB; //GestureLockView手指触摸的状态下内圆和外圆的颜色 private int mFingerOnColor = 0xFF378FC9; //GestureLockView手指抬起的状态下内园和外圆的颜色 private int mFingerUpColor = 0xFFFF0000; //宽度和高度 private int mWidth,mHeight; private Path mPath; //指引线的开始位置x private int mLastPathX; //指引线的开始位置y private int mLastPathY; //指引线的结束位置 private Point mTmpTarget = new Point(); //最大尝试次数 private int mTryTimes = 4; //回调接口 private OnGestureLockViewListener mOnGestureLockViewListener; public GestureLockViewGoup(Context context, AttributeSet attrs) { this(context, attrs,0); } public GestureLockViewGoup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GestureLockViewGroup, defStyleAttr, 0); int indexCount = typedArray.getIndexCount(); for (int i = 0; i < indexCount; i++) { int attr = typedArray.getIndex(i); switch (attr){ case R.styleable.GestureLockViewGroup_color_no_finger_inner_circle: mNoFingerInnerCircleColor = typedArray.getColor(attr, mNoFingerInnerCircleColor); break; case R.styleable.GestureLockViewGroup_color_no_finger_outer_circle: mNoFingerOuterCircleColor = typedArray.getColor(attr,mNoFingerOuterCircleColor); break; case R.styleable.GestureLockViewGroup_color_finger_on: mFingerOnColor = typedArray.getColor(attr,mFingerOnColor); break; case R.styleable.GestureLockViewGroup_color_finger_up: mFingerUpColor = typedArray.getColor(attr,mFingerUpColor); break; case R.styleable.GestureLockViewGroup_count: mCount = typedArray.getInt(attr,3); break; case R.styleable.GestureLockViewGroup_tryTimes: mTryTimes = typedArray.getInt(attr,5); break; default: break; } } typedArray.recycle(); //初始化画笔 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeJoin(Paint.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); mHeight = mWidth = mWidth<mHeight?mWidth:mHeight; //初始化mGestureLockViews if(mGestureLockViews == null){ mGestureLockViews = new GestureLockView[mCount*mCount]; //计算每个GestureLockView的宽度 mGestureLockViewWidth = (int)(4*mWidth*1.0f/(5*mCount+1)); //计算每个GestureLockView的间距 mMaginBetweenLockView = (int) (mGestureLockViewWidth*0.25); //设置画笔的宽度为GestureLockView的内园直径稍微小点 mPaint.setStrokeWidth(mGestureLockViewWidth*0.29f); for (int i = 0; i < mGestureLockViews.length; i++) { //初始化每个GestureLockView mGestureLockViews[i] = new GestureLockView(getContext(),mNoFingerInnerCircleColor,mNoFingerOuterCircleColor,mFingerOnColor,mFingerUpColor); mGestureLockViews[i].setId(i+1); //设置参数,主要是定位GestureLockView间的位置 RelativeLayout.LayoutParams lockerParams = new RelativeLayout.LayoutParams(mGestureLockViewWidth,mGestureLockViewWidth); //不是每行的第一个,则设置为前一个的右边 if(i%mCount != 0){ lockerParams.addRule(RelativeLayout.RIGHT_OF,mGestureLockViews[i-1].getId()); } //从第二行开始,设置为上一行同一位置View的下面 if(i>mCount - 1){ lockerParams.addRule(RelativeLayout.BELOW,mGestureLockViews[i - mCount].getId()); } //设置右下左上的边距 int rightMargin = mMaginBetweenLockView; int bottomMargin = mMaginBetweenLockView; int leftMargin = 0; int topMargin = 0; //每个view都有右外边距和底外边距,第一行的有上外边距 第一列的有左外边距 if(i>=0 && i<mCount){ //第一行 topMargin = mMaginBetweenLockView; } if(i%mCount == 0){//第一列 leftMargin = mMaginBetweenLockView; } lockerParams.setMargins(leftMargin,topMargin,rightMargin,bottomMargin); mGestureLockViews[i].setMode(GestureLockView.Mode.STATUS_FINGER_ON); addView(mGestureLockViews[i],lockerParams); } } } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); int x = (int) event.getX(); int y = (int) event.getY(); switch (action){ case MotionEvent.ACTION_DOWN: //重置 reset(); break; case MotionEvent.ACTION_MOVE: mPaint.setColor(mFingerOnColor); mPaint.setAlpha(50); GestureLockView child = getChildIdByPos(x,y); if(child != null){ int cId = child.getId(); if(!mChose.contains(cId)){ mChose.add(cId); child.setMode(GestureLockView.Mode.STATUS_FINGER_ON); if(mOnGestureLockViewListener != null){ mOnGestureLockViewListener.onBlockSelected(cId); } //设置指引线的起点 mLastPathX = child.getLeft()/2 +child.getRight()/2; mLastPathY = child.getTop()/2 + child.getBottom()/2; if(mChose.size() == 1){//当前添加为第一个 mPath.moveTo(mLastPathX,mLastPathY); }else{ //非第一个,将两者使用线连上 mPath.lineTo(mLastPathX,mLastPathY); } } } //指引线的终点 mTmpTarget.x = x; mTmpTarget.y = y; break; case MotionEvent.ACTION_UP: mPaint.setColor(mFingerUpColor); mPaint.setAlpha(50); this.mTryTimes--; //回调是否除成功 if(mOnGestureLockViewListener != null && mChose.size() > 0 ){ mOnGestureLockViewListener.onGestureEvent(checkAnswer()); if(this.mTryTimes == 0){ mOnGestureLockViewListener.onUnmatchedExceedBoundary(); } } //将终点设置为起点,即取消指引线 mTmpTarget.x = mLastPathX; mTmpTarget.y = mLastPathY; //改变子元素的状态为UP changeItemMode(); //计算每个元素中箭头需要旋转的角度 for (int i = 0; i < mChose.size() - 1; i++) { int childId = mChose.get(i); int nextChildId = mChose.get(i+1); GestureLockView startChild = (GestureLockView) findViewById(childId); GestureLockView nextChild = (GestureLockView) findViewById(nextChildId); int dx = nextChild.getLeft() - startChild.getLeft(); int dy = nextChild.getTop() - startChild.getTop(); //计算角度 int angle = (int) Math.toDegrees(Math.atan2(dy,dx)) + 90; startChild.setArrowDegree(angle); } break; } invalidate(); return true; } private void changeItemMode() { for(GestureLockView gestureLockView : mGestureLockViews){ if(mChose.contains(gestureLockView.getId())){ gestureLockView.setMode(GestureLockView.Mode.STATUS_FINGER_UP); } } } /** * 检查用户绘制的手势是否正确 * @return */ private boolean checkAnswer() { if(mAnswer.length != mChose.size()) return false; for (int i = 0; i < mAnswer.length; i++) { if(mAnswer[i] != mChose.get(i)) return false; } return true; } /** * 检查当前左边是否在child中 * @param child * @param x * @param y * @return */ private boolean checkPostionInChild(View child,int x,int y){ //设置了内边距,即x,y必须落入下GestureLockView的内部中间的小区域中,可以通过调整使得x,y落入范围不变大,或者不设置padding int padding = (int)(mGestureLockViewWidth*0.15); if(x>= child.getLeft() +padding && x<= child.getRight() - padding && y>= child.getTop() + padding && y<= child.getBottom() - padding){ return true; } return false; } /** * 通过x,y获得落入的GestureLockView * @param x * @param y * @return */ private GestureLockView getChildIdByPos(int x, int y) { for(GestureLockView gestureLockView :mGestureLockViews){ if(checkPostionInChild(gestureLockView,x,y)){ return gestureLockView; } } return null; } /** * 做一些必要的重置 */ private void reset() { mChose.clear(); mPath.reset(); for(GestureLockView gestureLockView : mGestureLockViews){ gestureLockView.setMode(GestureLockView.Mode.STATUS_NO_FINGER); gestureLockView.setArrowDegree(-1); } } /** * 设置回调接口 * @param listener */ public void setOnGestureLockViewListener(OnGestureLockViewListener listener){ this.mOnGestureLockViewListener = listener; } /** * 对外公布设置答案的方法 * @param answer */ public void setAnswer(int[] answer){ this.mAnswer = answer; } public void setUnMatchExceedBoundary(int boundary){ this.mTryTimes = boundary; } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); //绘制GestureLockView间的连线 if(mPath != null){ canvas.drawPath(mPath,mPaint); } //绘制指引线 if(mChose.size()>0){ if(mLastPathX != 0 && mLastPathY != 0){ canvas.drawLine(mLastPathX,mLastPathY,mTmpTarget.x,mTmpTarget.y,mPaint); } } } public interface OnGestureLockViewListener{ /** * 单独选中元素的ID * */ void onBlockSelected(int cId); /** * 是否匹配 * */ void onGestureEvent(boolean matched); /** * 超过测试尝试 * */ void onUnmatchedExceedBoundary(); } }
在xml文件布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xxl="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.administrator.testapplication.MainActivity"> <com.example.administrator.testapplication.GestureLockViewGoup android:id="@+id/id_gestureLockViewGroup" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#F2F2F7" android:gravity="center_vertical" xxl:count="3" xxl:tryTimes="5" > </com.example.administrator.testapplication.GestureLockViewGoup> </RelativeLayout >
在Activity中使用
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final GestureLockViewGoup mGestureLockViewGroup = (GestureLockViewGoup) findViewById(R.id.id_gestureLockViewGroup); mGestureLockViewGroup.setAnswer(new int[]{1,2,3,4,5}); mGestureLockViewGroup.setOnGestureLockViewListener(new GestureLockViewGoup.OnGestureLockViewListener() { @Override public void onBlockSelected(int cId) { mGestureLockViewGroup.setUnMatchExceedBoundary(5); } @Override public void onGestureEvent(boolean matched) { Toast.makeText(MainActivity.this, matched+"", Toast.LENGTH_SHORT).show(); } @Override public void onUnmatchedExceedBoundary() { } }); } }
相关文章推荐
- socket 访问百度
- c++ 类型转换
- jqgrid
- HDOJ/HDU 1022 Train Problem I(模拟栈)
- HDOJ/HDU 1022 Train Problem I(模拟栈)
- C++11模板类使用心得
- 单片机最小系统及其原理图
- 深入浅出RxJava(一:基础篇)
- PAT: 1001. A+B Format (20)
- MFC
- 多线程
- 第十六周项目2—阅读程序(1)
- 设计模式:Observer(观察者)—— Guava EventBus
- 处理MariaDB Galera cluster初始化和启动报错两例
- 使用python脚本备份crontab定时任务
- java代码添加view
- Map的数据结构
- win10中显示资源管理器扩展
- 字符串分割与存入List集合
- ajax跨域请求结合springmvc后台代码学习整理