如何设置onDraw绘制的自定义View的尺寸与位置并解决显示异常?
问题解决步骤
1. 修复自定义View不显示的问题
你添加onMeasure和onLayout后视图消失,核心原因是**onLayout实现错误**,以及onMeasure未正确处理测量约束:
移除错误的onLayout重写
FrameLayout会自动管理子视图的布局位置,强行在onLayout中指定oval的坐标会导致视图被放置到父容器可视区域外(比如oval.left/oval.top数值过大),直接删掉onLayout的重写代码即可。
正确实现onMeasure
基于oval的宽高确定视图自身尺寸,同时兼容父容器的测量约束:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 基于oval计算视图理想宽高 int desiredWidth = (int) (oval.right - oval.left); int desiredHeight = (int) (oval.bottom - oval.top); // 解析父容器测量规格 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); // 确定最终宽度 int width; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else if (widthMode == MeasureSpec.AT_MOST) { width = Math.min(desiredWidth, widthSize); } else { width = desiredWidth; } // 确定最终高度 int height; if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else if (heightMode == MeasureSpec.AT_MOST) { height = Math.min(desiredHeight, heightSize); } else { height = desiredHeight; } setMeasuredDimension(width, height); }
2. 在FrameLayout中放置多个ScArc视图
每个ScArc实例需通过LayoutParams的margin属性控制在父容器中的位置:
// 创建ScArc实例 ScArc arc = new ScArc(context, X1, Y1, X2, Y2, azimuth, sweepAngle, ...); // 创建FrameLayout布局参数 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT ); // 设置margin对应oval左上角坐标,实现视图定位 params.leftMargin = (int) oval.left; params.topMargin = (int) oval.top; // 绑定参数并添加到FrameLayout arc.setLayoutParams(params); frameLayout.addView(arc);
3. 为每个ScArc绑定SimpleOnGestureListener
在ScArc构造方法中初始化手势检测器,并在onTouchEvent中对接逻辑:
public class ScArc extends View { private GestureDetector gestureDetector; public ScArc(Context context, float X1, float Y1, float X2, float Y2, ScMain.Azimuth azimuth, int sweepAngle, String strokeWidthName, String strokeColorName, int idx, boolean isForcingChain) { super(context); // ... 原有初始化代码 ... // 初始化手势检测器 gestureDetector = new GestureDetector(context, new SimpleOnGestureListener() { @Override public boolean onDown(MotionEvent e) { return true; // 返回true才能触发后续手势 } @Override public boolean onSingleTapUp(MotionEvent e) { // 处理单击事件 return super.onSingleTapUp(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // 处理滚动事件 return super.onScroll(e1, e2, distanceX, distanceY); } // 根据需求添加其他手势方法(如onLongPress) }); this.setClickable(true); this.setEnabled(true); } @Override public boolean onTouchEvent(MotionEvent event) { // 保留右键移除逻辑 if (((event.getSource() == SOURCE_MOUSE) || (event.getSource() == SOURCE_TOUCHPAD)) && (event.getAction() == MotionEvent.ACTION_DOWN) && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)) { int tag = (int) this.getTag(); drawnStrongLinks.remove(drawnStrongLinks.indexOf(tag)); FrameLayout drawingFrame = (FrameLayout) this.getParent(); drawingFrame.removeView(this); return true; } // 让手势检测器处理其他事件 return gestureDetector.onTouchEvent(event) || super.onTouchEvent(event); } // ... 原有onDraw、onMeasure代码 ... }
额外注意事项
drawnStrongLinks若为全局集合,需确保在UI线程操作,避免并发问题;- 检查
Paint的颜色、线条宽度等设置,避免因样式问题导致绘制内容不可见。
内容的提问来源于stack exchange,提问作者ema3272
相关产品推荐
相关产品推荐

