Android 自定义View之手势解锁控件 – 源码巴士 您所在的位置:网站首页 安卓自定义button Android 自定义View之手势解锁控件 – 源码巴士

Android 自定义View之手势解锁控件 – 源码巴士

2023-04-28 15:44| 来源: 网络整理| 查看: 265

前言:Android有很多原生控件供开发者使用,但是原生控件使用起来也有局限性,这个时候呢Android也有给开发者提供一些方式来根据需求进行自定义,今天介绍自定义控件之手势解锁控件,效果如图在这里插入图片描述 九宫格手势解锁控件是目前用得最广泛的控件,先介绍一下实现思路;九宫格是基于容器来的 所以我们可以在自定义的时候继承与ViewGroup来实现,然后再ViewGroup里面构建出连线时需要的点,最后再构建需要连接的线和保存选中的点和线的走向。 接下来看看实现: 步骤一:定义一个类继承与RelativeLayout 步骤二:定义出画笔和点的坐标、颜色、以及存储和答案 步骤三:测量控件的宽高和通过计算出的间距添加到布局中

private void setLockViewParams(LockViewFactory lockViewFactory) { if (mILockViews.size() > 0) { return; } if (mLockViewMargin == 0) { mLockViewMargin = (DisplayUtils.dp2px(getContext(), 250) - mLockViewWidth * mDotCount) / (mDotCount - 1); } for (int i = 0; i < mDotCount * mDotCount; i++) { ILockView iLockView = lockViewFactory.newLockView(); iLockView.getView().setId(i + 1); mILockViews.add(iLockView); RelativeLayout.LayoutParams lockerParams = new LayoutParams(mLockViewWidth, mLockViewWidth); //不是每行的第一个,则设置位置为前一个的右边 if (i % mDotCount != 0) { lockerParams.addRule(RelativeLayout.RIGHT_OF, mILockViews.get(i - 1).getView().getId()); } //从第二行开始,设置为上一行同一位置View的下面 if (i > mDotCount - 1) { lockerParams.addRule(RelativeLayout.BELOW, mILockViews.get(i - mDotCount).getView().getId()); } //设置右下左上的边距 int rightMargin = 0; int bottomMargin = 0; int leftMargin = 0; int topMargin = 0; //每个View都有右外边距和底外边距 第一行的有上外边距 第一列的有左外边距 if (i >= mDotCount) {//非第一行 topMargin = mLockViewMargin; } if (i % mDotCount != 0) {//非第一列 leftMargin = mLockViewMargin; } lockerParams.setMargins(leftMargin, topMargin, rightMargin, bottomMargin); mILockViews.get(i).onNoFinger(); mILockViews.get(i).getView().setLayoutParams(lockerParams); addView(mILockViews.get(i).getView()); } }

步骤四:处理按下和移动 抬起事件

@Override public boolean onTouchEvent(MotionEvent event) { if (mTouchable) { int action = event.getAction(); int x = (int) event.getX(); int y = (int) event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: handleDownEvent(x, y); break; case MotionEvent.ACTION_MOVE: handleMoveEvent(x, y); break; case MotionEvent.ACTION_UP: handleUpEvent(); break; } invalidate(); return true; } else { return false; } }

按下时需要复位View,处理移动事件

private void handleMoveEvent(int x, int y) { mPaint.setColor(mFingerTouchColor); ILockView lockView = getLockViewByPoint(x, y); if (lockView != null) { int childId = lockView.getView().getId(); if (!mChooseList.contains(childId)) { mChooseList.add(childId); lockView.onFingerTouch(); //手势解锁监听 if (mOnLockVerifyListener != null) { mOnLockVerifyListener.onGestureSelected(childId); } mLastPathX = lockView.getView().getLeft() / 2 + lockView.getView().getRight() / 2; mLastPathY = lockView.getView().getTop() / 2 + lockView.getView().getBottom() / 2; if (mChooseList.size() == 1) { mPath.moveTo(mLastPathX, mLastPathY); } else { mPath.lineTo(mLastPathX, mLastPathY); } } } //指引线终点坐标 mLineX = x; mLineY = y; }

处理抬起事件:

private void handleUpEvent() { if (mCurrentMode == RESET_MODE) { handleResetMode(); } else { handleVerifyMode(); } //将指引线的终点坐标设置为最后一个Path的原点,即取消指引线 mLineX = mLastPathX; mLineY = mLastPathY; }

步骤五:记录和保存

@Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.tryTimes = mTryTimes; return ss; }

步骤六:校验

/** * 检查答案是否正确 */ private boolean checkAnswer() { if (mAnswerList.size() != mChooseList.size()) { return false; } for (int i = 0; i < mAnswerList.size(); i++) { if (mAnswerList.get(i) != mChooseList.get(i) - 1) { return false; } } return true; } /** * 切换LockView是否匹配状态 */ private void toggleLockViewMatchedState(boolean isMatched) { if (isMatched) { mPaint.setColor(mFingerUpMatchedColor); } else { mPaint.setColor(mFingerUpUnmatchedColor); } for (ILockView iLockView : mILockViews) { if (mChooseList.contains(iLockView.getView().getId())) { if (!isMatched) { iLockView.onFingerUpUnmatched(); } else { iLockView.onFingerUpMatched(); } } } }

OK,结束 代码已经上传到 我的资源



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有