手势在绘制手势的过程中,View是如何判断手指当前位置是否选中某个 Cell ,以及是否应该把该 Cell 连接入手势。这里需要了解几个函数:
用来确定手指当前坐标 (x, y) 位于九宫格的第几排。
用来确定手指当前坐标 (x, y) 位于九宫格的第几列。
- getRowHit ( float y )
用来确定手指当前坐标 (x, y) 位于九宫格的第几排。
- getColumnHit (float x )
用来确定手指当前坐标 (x, y) 位于九宫格的第几列。
- checkForNewHit (float x, float y)
private Cell checkForNewHit(float x, float y) { final int rowHit = getRowHit(y); if (rowHit < 0) { return null; } final int columnHit = getColumnHit(x); if (columnHit < 0) { return null; } if (mPatternDrawLookup[rowHit][columnHit]) { return null; } return Cell.of(rowHit, columnHit); }
函数代码很好理解,mPatternDrawLookup 是个全局变量,同样采用矩阵的形式,用于标记九宫格中哪个 Cell 被连接。从 checkForNewHit 中可以看出,已经被连接的 Cell,是不会再被选中的,这也是目前手势密码普遍的做法。如果你需要实现“每个点可以被连接多次”的需求,这部分就需要改动了。
用来检测并判断手指当前坐标 (x, y) 是否需要添加添加进当前手势中。
判断条件是:当前 Cell 与手势中最后一个 Cell 的行或者列的绝对差值为 2,且其列或行的绝对差值不为1,即两个 Cell 不相邻(包括水平、竖直、45°方向的相邻),获得当前 Cell 与手势中最后一个 Cell 之间的 Cell,如果该 Cell 没有被添加进去过,则添加进手势。
意思就是说,绘制的手势不会跨过没有添加的点。
- detectAndAddHit (float x, float y)
用来检测并判断手指当前坐标 (x, y) 是否需要添加添加进当前手势中。
private Cell detectAndAddHit(float x, float y) { final Cell cell = checkForNewHit(x, y); if (cell != null) { // check for gaps in existing pattern Cell fillInGapCell = null; final ArrayList<Cell> pattern = mPattern; if (!pattern.isEmpty()) { final Cell lastCell = pattern.get(pattern.size() - 1); int dRow = cell.row - lastCell.row; int dColumn = cell.column - lastCell.column; int fillInRow = lastCell.row; int fillInColumn = lastCell.column; if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) { fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1); } if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) { fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1); } fillInGapCell = Cell.of(fillInRow, fillInColumn); } if (fillInGapCell != null && !mPatternDrawLookup[fillInGapCell.row][fillInGapCell.column]) { addCellToPattern(fillInGapCell); } addCellToPattern(cell); if (mEnableHapticFeedback) { performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } return cell; } return null; }
首先通过 checkForNewHit 获得当前位置的的 Cell,计算当前Cell 与手势中最后一个 Cell 的行列差值。看其中一段代码
if (Math.abs(dRow) == 2 && Math.abs(dColumn) != 1) { fillInRow = lastCell.row + ((dRow > 0) ? 1 : -1); } if (Math.abs(dColumn) == 2 && Math.abs(dRow) != 1) { fillInColumn = lastCell.column + ((dColumn > 0) ? 1 : -1); } fillInGapCell = Cell.of(fillInRow, fillInColumn);
判断条件是:当前 Cell 与手势中最后一个 Cell 的行或者列的绝对差值为 2,且其列或行的绝对差值不为1,即两个 Cell 不相邻(包括水平、竖直、45°方向的相邻),获得当前 Cell 与手势中最后一个 Cell 之间的 Cell,如果该 Cell 没有被添加进去过,则添加进手势。
意思就是说,绘制的手势不会跨过没有添加的点。