0

我有一个自定义视图,允许我在创建它时在其上绘制位图,然后用户可以用手指在其上绘制。

我的问题是画布填充了我的布局中可用区域的整个宽度/高度,但我希望它简单地匹配绘制的位图的大小,以便用户只能在图片上绘制。这似乎需要在 onSizeChanged 中完成,因为如果它们从纵向变为横向,我需要调整位图的大小。等等

我的代码:

class DrawingCameraPanel extends View implements OnTouchListener {

    public Canvas mCanvas;
    private Path mPath;
    private Paint mPaint;
    private ArrayList<Path> paths = new ArrayList<Path>();
    private Bitmap background;
    int width;
    int height;

    public Bitmap getOutputBitmap() {
        Bitmap.Config config = Bitmap.Config.RGB_565;
        Bitmap bitmap = Bitmap.createBitmap(width, height, config);
        Canvas canvas = new Canvas(bitmap);
        onDraw(canvas);
        return bitmap;
    }

    public DrawingCameraPanel(Context context) {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setOnTouchListener(this);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(6);
    }

    public DrawingCameraPanel(Context context, AttributeSet attrs) {
        super(context, attrs);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setOnTouchListener(this);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(6);
    }

    public DrawingCameraPanel(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setOnTouchListener(this);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(6);
    }

    public void setPaintColor(int color) {
        mPaint.setColor(color);
    }

    public void setBackgroundPic(Bitmap bitmap) {
        this.background = bitmap;
        mCanvas = new Canvas();
        mPath = new Path();
        paths.add(mPath);
        mCanvas.save();
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
        background = resizeImage(background, w, h);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (background != null) {
            canvas.drawBitmap(background, 0, 0, null);
        }
        for (Path p : paths) {
            canvas.drawPath(p, mPaint);
        }
    }

    public Bitmap resizeImage(Bitmap image, int maxWidth, int maxHeight) {
        Bitmap resizedImage = null;
        try {
            int imageHeight = image.getHeight();

            if (imageHeight > maxHeight)
                imageHeight = maxHeight;
            int imageWidth = (imageHeight * image.getWidth())
                    / image.getHeight();

            if (imageWidth > maxWidth) {
                imageWidth = maxWidth;
                imageHeight = (imageWidth * image.getHeight())
                        / image.getWidth();
            }

            if (imageHeight > maxHeight)
                imageHeight = maxHeight;
            if (imageWidth > maxWidth)
                imageWidth = maxWidth;

            resizedImage = Bitmap.createScaledBitmap(image, imageWidth,
                    imageHeight, true);
        } catch (OutOfMemoryError e) {

            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resizedImage;
    }

    public void clear() {
        this.paths.clear();
        mPath = new Path();
        paths.add(mPath);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath = new Path();
        paths.add(mPath);
    }

    @Override
    public boolean onTouch(View arg0, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up();
            invalidate();
            break;
        }
        return true;
    }
4

1 回答 1

1

当然,Canvas如果布局的宽度和高度(很可能)设置为match_parentor ,为什么不占用布局中的所有空间fill_parent?(好吧,从技术上讲:View- 调整边界的是视图,而画布只是“跟随”它们)。

我认为你在这里重新发明轮子。我建议不要自己编写所有代码,而是:

  • 子类ImageView而不是View.
  • 调用setAdjustViewBounds(true)构造函数。这是重要的部分。这实际上将更改视图的边界以匹配包含的图像 - 它保留纵横比并确保图像适合布局提供的空间。
  • 由于用户绘制的背景是透视图像源,因此setBackgroundPic()只需调用即可。ImageView.setImageBitmap()ImageView
  • 保留所有绘图代码 - 即OnTouchListener实现。

这里很酷的是您的自定义视图现在会自动调整大小。因此,您不必担心允许用户绘制的范围,因为它们会为您设置。

于 2013-02-06T17:19:24.223 回答