You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 01:42:23