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_parentfill_parent?(技術的には:View-境界を調整しているのはビューであり、キャンバスは境界を「追跡」しているだけです)。

ここで車輪の再発明をしていると思います。すべてのコードを自分で書く代わりに、次のことをお勧めします。

  • ImageViewの代わりにサブラスView
  • setAdjustViewBounds(true)コンストラクターを呼び出します。これは重要な部分です。これにより、実際には、含まれている画像に一致するようにビューの境界が変更されます。アスペクト比が維持され、レイアウトが提供するスペースに画像が確実に収まるようになります。
  • ユーザーが描く背景は遠近法による画像ソースであるため、setBackgroundPic()単純に呼び出すようにします。ImageView.setImageBitmap()ImageView
  • すべての描画コードをそのままにします-つまり、OnTouchListener実装です。

ここですばらしいのは、カスタムビューのサイズが自動的に変更されることです。したがって、ユーザーがペイントできる境界について心配する必要はありません。境界が設定されるからです。

于 2013-02-06T17:19:24.223 に答える