Android自定义View设置线条高度极值及两线夹角计算问询
为自定义View的线条高度设置范围 + 计算直线夹角思路
一、限制线条高度的最大值与最小值
看你的代码,是通过触摸滑动改变lineOneEnd的Y值来调整左侧竖线的高度(线条高度为lineOneEnd - lineOneStart,也就是lineOneEnd - 50f)。要给这个高度设置上下限,只需要在更新lineOneEnd的时候,用Math.max()和Math.min()把数值限制在你想要的区间内就好。
比如我假设你希望线条的最小高度是50(对应lineOneEnd最小为100f),最大高度是250(对应lineOneEnd最大为300f),你可以这样修改onTouchEvent方法里的逻辑:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (touchArea.contains(event.getX(), event.getY())) { currentTouch = TOUCH_TOP_LEFT; Toast.makeText(getContext(), "tf" + currentTouch, Toast.LENGTH_SHORT).show(); } else { return false; } return true; case MotionEvent.ACTION_MOVE: switch (currentTouch) { case TOUCH_TOP_LEFT: // 获取触摸的Y值,然后限制在100f到300f之间 float newY = event.getY(); lineOneEnd = Math.max(100f, Math.min(newY, 300f)); invalidate(); return true; } return false; case MotionEvent.ACTION_UP: switch (currentTouch) { case TOUCH_TOP_LEFT: float newY = event.getY(); lineOneEnd = Math.max(100f, Math.min(newY, 300f)); currentTouch = NONE; invalidate(); return true; } return false; } return false; }
原理说明:
Math.min(newY, 300f)确保lineOneEnd不会超过最大值300f,避免线条过高;Math.max(100f, ...)确保lineOneEnd不会低于最小值100f,避免线条过短;- 你可以根据自己的需求,把100f和300f改成任意符合业务逻辑的数值。
二、计算两条直线夹角的思路
计算两条直线的夹角,最常用的是向量点积公式,步骤如下:
- 获取两条直线的方向向量:每条直线取两个端点,用终点坐标减去起点坐标得到方向向量;
- 计算向量点积:两个向量的x分量相乘加上y分量相乘;
- 计算向量的模长:每个向量的x、y分量平方和开根号;
- 通过点积公式求余弦值:余弦值 = 点积 / (两个向量模长的乘积);
- 转成角度:用反余弦函数得到弧度,再转成角度,最后取0-90度的锐角(因为直线夹角通常指最小的那个角)。
示例代码:
你可以在你的Line类里添加这个方法来计算夹角:
private float calculateLineAngle(PointF line1Start, PointF line1End, PointF line2Start, PointF line2End) { // 计算两条直线的方向向量 float vec1X = line1End.x - line1Start.x; float vec1Y = line1End.y - line1Start.y; float vec2X = line2End.x - line2Start.x; float vec2Y = line2End.y - line2Start.y; // 计算点积 float dotProduct = vec1X * vec2X + vec1Y * vec2Y; // 计算两个向量的模长 float vec1Length = (float) Math.sqrt(vec1X * vec1X + vec1Y * vec1Y); float vec2Length = (float) Math.sqrt(vec2X * vec2X + vec2Y * vec2Y); // 处理向量长度为0的异常情况(比如直线是一个点) if (vec1Length == 0 || vec2Length == 0) { return 0f; } // 计算余弦值,限制在[-1,1]范围内,避免浮点计算误差导致超出范围 float cosTheta = Math.max(-1f, Math.min(dotProduct / (vec1Length * vec2Length), 1f)); // 转成弧度再转成角度 float angleRadians = (float) Math.acos(cosTheta); float angleDegrees = (float) Math.toDegrees(angleRadians); // 返回最小的夹角(0-90度) return Math.min(angleDegrees, 180 - angleDegrees); }
使用示例:
比如你想计算左侧竖线(lineOne)和底部横线的夹角,可以这样调用:
// lineOne的两个点:(lineOneStartx, lineOneStart) 和 (lineOneEndx, lineOneEnd) // 底部横线的两个点:(lineOneEndx, lineOneEnd) 和 (lineTwoEndx, lineTwoEnd) float angle = calculateLineAngle( new PointF(lineOneStartx, lineOneStart), new PointF(lineOneEndx, lineOneEnd), new PointF(lineOneEndx, lineOneEnd), new PointF(lineTwoEndx, lineTwoEnd) );
内容的提问来源于stack exchange,提问作者Rnld
相关产品推荐
相关产品推荐

