【问题标题】:Draw on the custom image view in android在android中绘制自定义图像视图
【发布时间】:2015-01-22 17:04:32
【问题描述】:

我正在开发一个绘图应用程序。而且我已经创建了一个允许用户在视图上绘图的绘图视图。

问题是,当我在上面画的时候,它超出了图像的面积(请参考图片,黄线超出了实际的照片区域),我怎样才能将画布大小粘贴到实际的图像上?

以及如何缩放图像视图?这意味着当用户单击笔按钮时,它会绘制,当用户再次单击时,它会成为缩放功能。

谢谢。缩放功能可以稍后解决,超出区域的问题需要先解决

这是 xml 中的自定义绘制视图

  <com.example.tool.DrawView
        android:id="@+id/draw"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

这里是java

public class DrawView extends ImageView {

    private int color = Color.BLACK;
    private float width = 4f;
    private List<Holder> holderList = new ArrayList<Holder>();

    private class Holder {      
        Path path;
        Paint paint;

        Holder(int color, float width) {
            path = new Path();
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStrokeWidth(width);
            paint.setColor(color);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeCap(Paint.Cap.ROUND);
        }
    }

    public DrawView(Context context) {
        super(context);
        init();
    }

    public DrawView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DrawView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        holderList.add(new Holder(color, width));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (Holder holder : holderList) {
            canvas.drawPath(holder.path, holder.paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float eventX = event.getX();
        float eventY = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                holderList.add(new Holder(color,width));
                holderList.get(holderList.size() - 1).path.moveTo(eventX, eventY);
                return true;
            case MotionEvent.ACTION_MOVE:
                holderList.get(holderList.size() - 1).path.lineTo(eventX, eventY);
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                return false;
        }

        invalidate();
        return true;
    }

    public void resetPaths() {
        for (Holder holder : holderList) {
            holder.path.reset();
        }
        invalidate();
    }

    public void setBrushColor(int color) {
        this.color = color;
    }

    public void setWidth(float width) {
        this.width = width;
    }
}

我叫它:

DrawView pic = findViewById(R.id.draw);
pic.setImageBitmap(bitmap);

非常感谢您的帮助

【问题讨论】:

    标签: android canvas android-imageview android-view android-drawable


    【解决方案1】:

    先计算显示的图像大小,然后将 eventX 和 eventY 夹在显示图像的边界上。代码如下:

       int imageViewH=imageView.getMeasuredHeight();//height of imageView
       int imageViewW =imageView.getMeasuredWidth();//width of imageView
       int drawableH =imageView.getDrawable().getIntrinsicHeight();//original height of underlying image
       int drawableW=imageView.getDrawable().getIntrinsicWidth();//original width of underlying image
       int displayH, displayW;  // the shown height and width of the picture.
       int leftX, rightX, topY, bottomY; // the shown edges of the picture.
       if (imageViewH/drawableH <= imageViewW/drawableW){
           displayW = drawableW*imageViewH/drawableH;//rescaled width of image within ImageView
           displayH = imageViewH;
           leftX = (imageViewW - displayW)/2; // left edge of the displayed image.
           rightX = leftX + displayW; // right edge of the displayed image.
           topY = 0; // top edg
           bottomY = displayH; // bottom edge.
       }else{
           displayH = drawableH*imageViewW/drawableH;//rescaled height of image within ImageView
           displayW = imageViewW;
           leftX = 0; // left edge of the displayed image.
           rightX = displayW; // right edge of the displayed image.
           topY = (imageViewH - displayH)/2; // top edg
           bottomY = topY + displayH; // bottom edge.
       }
       //TODO: clamp the eventX and eventY to the bound of leftX, rightX, topY, bottomY
    

    注意:代码仅应在您的 ImageView 具有测量高度和可绘制对象后使用。

    【讨论】:

    • 是的,我可以在缩放后返回宽度和高度。对不起,我猜代码放在主要活动中?在我得到 H、W、leftX、rightX、topY、bottomY 之后,你介意解释一下如何设置画布吗?谢谢
    • 我认为代码可以在onTouchEvent中使用,但我不确定这是否是最有效的方式。而且这是一种不缩放计算显示图片绑定的方法,缩放后需要改变计算方式。
    • 我已经测试过将代码放到自定义视图的触屏案例中,但这是否意味着我也需要从主活动中传入 imageView?由于自定义绘图视图中不存在 imageview ,并且钳位事件 X Y 意味着在添加绘图持有人列表之前检查它是否超出区域?抱歉问了这么多问题。感谢您的帮助
    • 不,你不需要传递imageView。由于您在 DrawView 中使用代码,因此 imageView 等于“this”。钳位事件 X Y 的意思是确保你传递给 path.moveTo() 和 path.lineTo() 方法的参数不会超过图片的区域。
    【解决方案2】:

    如果在 ImageView 的属性中有一个真正的属性 adjustViewBounds,您可以通过编程将 DrawView 的宽度设置为 ImageView 的宽度。

    【讨论】:

    • 谢谢,我现在在我的 xml 中添加了 adjustViewBound,如果有一些关于“以编程方式将 DrawView 的宽度设置为 ImageView 的宽度”的代码会更好
    • 我认为你可以限制画线区域: MotionEvent.ACTION_MOVE: holderList.get(holderList.size() - 1).path.lineTo(eventX, eventY);休息;
    最近更新 更多