最近在做相冊的圖片編輯功能,遇到一個bug,插入文字後旋轉文字區域,點擊文字區域無法觸發,分析原因是判斷時認定爲點沒在RectF內。如圖:
如果只是通過rect.contains(x, y)來判斷,那麼實際區域則是綠色區域的部分,則有部分無法點擊,如下圖:
因此需要將矩形框旋轉。
如果通過matrix.mapRect(rect)來獲取轉換後的區域,再通過rect.contains(x, y)來判斷是否落在區域內,那麼實際區域如下圖綠色區域,則點擊非區域內的位置仍會觸發文字區域的點擊,如下圖:
Matrix matrix = new Matrix();
matrix.setRotate(roatetAngle, mHelpBoxRect.centerX(), mHelpBoxRect.centerY());
matrix.mapRect(mHelpBoxRect);
因此,無法通過rect.contains(x, y)來判斷點是否落在區域內。需要將原矩形四個頂點旋轉,將轉換後的矩形四個頂點重新構成四邊形,再判斷點是否落在該四邊形內。
public boolean clickHelpBoxRect(float x, float y) {
if (mHelpBoxRect == null || mHelpBoxRect.isEmpty()) {
return false;
}
boolean isClickHelpBoxRect;
if (roatetAngle != 0) {
// 旋轉後判斷點是否在四邊形內
Matrix matrix = new Matrix();
matrix.setRotate(roatetAngle, mHelpBoxRect.centerX(), mHelpBoxRect.centerY());
PointF curPoint = new PointF(x, y);
PointF pointLT = getMapPoints(matrix, mHelpBoxRect.left, mHelpBoxRect.top);
PointF pointRT = getMapPoints(matrix, mHelpBoxRect.right, mHelpBoxRect.top);
PointF pointLB = getMapPoints(matrix, mHelpBoxRect.left, mHelpBoxRect.bottom);
PointF pointRB = getMapPoints(matrix, mHelpBoxRect.right, mHelpBoxRect.bottom);
isClickHelpBoxRect = pointInRect(curPoint, pointLT, pointRT, pointLB, pointRB);
} else {
isClickHelpBoxRect = mHelpBoxRect.contains(x, y);
}
return isClickHelpBoxRect;
}
/**
* 獲取旋轉後的座標點
*
* @param matrix 轉換矩陣
* @param x 左座標
* @param y 右座標
* @return
*/
private PointF getMapPoints(Matrix matrix, float x, float y) {
float[] floats = new float[]{x, y};
matrix.mapPoints(floats);
return new PointF(floats[0], floats[1]);
}
/**
* 點是否落在四邊形內
*
* @param curPoint 點擊位置
* @param pointLT 左上頂點
* @param pointRT 右上頂點
* @param pointLB 左下頂點
* @param pointRB 右下頂點
* @return true 在四邊形內;false 不在四邊形內
*/
private boolean pointInRect(PointF curPoint, PointF pointLT, PointF pointRT, PointF pointLB, PointF pointRB) {
int nCount = 4;
PointF[] rectPoints = new PointF[]{pointLT, pointLB, pointRB, pointRT};
int nCross = 0;
for (int i = 0; i < nCount; i++) {
//依次取相鄰的兩個點
PointF pStart = rectPoints[i];
PointF pEnd = rectPoints[(i + 1) % nCount];
//相鄰的兩個點是平行於x軸的,肯定不相交,忽略
if (pStart.y == pEnd.y)
continue;
//交點在pStart,pEnd的延長線上,pCur肯定不會與pStart.pEnd相交,忽略
if (curPoint.y < Math.min(pStart.y, pEnd.y) || curPoint.y > Math.max(pStart.y, pEnd.y))
continue;
//求當前點和x軸的平行線與pStart,pEnd直線的交點的x座標
double x = (double) (curPoint.y - pStart.y) * (double) (pEnd.x - pStart.x) / (double) (pEnd.y - pStart.y) + pStart.x;
//若x座標大於當前點的座標,則有交點
if (x > curPoint.x)
nCross++;
}
// 單邊交點爲偶數,點在多邊形之外
return (nCross % 2 == 1);
}