使用画布在自定义图像视图上绘制,缩放和拖动

时间:2016-06-20 13:51:41

标签: android canvas bitmap zoom draw

我需要参加的行为是保留我根据缩放级别绘制的内容。我能够使用针对同一问题的另一种解决方案Canvas - zooming in, shifting, and scaling on Android来实现此行为。然而,我遇到了一个可能听起来很荒谬的问题,但是我无法解决这个问题。 当我在主活动中调用imageView.setImageBitmap(位图b)时,从不显示位图。它总是显示一个白页来绘制。

请问,如何在这里的自定义视图中显示我的位图?

以下是代码:

ScaleImageView.java

public class ScaleImageView extends View {


private Bitmap imgBitmap = null;

private int containerWidth;
private int containerHeight;
float[] mv = new float[9];
Paint background;

Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();

PointF start = new PointF();

float currentScale;
float curX;
float curY;

//We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
float targetX;
float targetY;
float targetScale;
float targetScaleX;
float targetScaleY;
float scaleChange;
float targetRatio;
boolean isAnimating = false;
float oldDist = 1f;
PointF mid = new PointF();

private Handler mHandler = new Handler();

float minScale;
float maxScale = 8.0f;
float screenDensity;

private GestureDetector gestureDetector;

public static final int DEFAULT_SCALE_FIT_INSIDE = 0;

private int defaultScale;

private Path drawPath;
public Paint drawPaint;
private Canvas drawCanvas;
Rect clipBounds;

public ArrayList<Path> paths = new ArrayList<>();
public ArrayList<Paint> colors = new ArrayList<>();

// Creates Path and Paint for drawing
public void setUpDrawing() {

    drawPath = new Path();
    drawPaint = new Paint();
    drawPaint.setColor(Color.RED);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(8);
    drawPaint.setStyle(Paint.Style.STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);
}


public ScaleImageView(Context context) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);
    screenDensity = context.getResources().getDisplayMetrics().density;
    initPaints();
    gestureDetector = new GestureDetector(context, new MyGestureDetector());
    setUpDrawing();
}

public ScaleImageView(Context context, AttributeSet attrs) {
    super(context, attrs);

    screenDensity = context.getResources().getDisplayMetrics().density;
    initPaints();
    gestureDetector = new GestureDetector(context,new MyGestureDetector());

    defaultScale = ScaleImageView.DEFAULT_SCALE_FIT_INSIDE;
    setUpDrawing();
}

private void initPaints() {
    background = new Paint();
    setUpDrawing();
}

@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
    super.onSizeChanged(width, height, oldWidth, oldHeight);

    containerWidth = width;
    containerHeight = height;

    if (imgBitmap != null) {
        drawCanvas = new Canvas(imgBitmap);
        int imgHeight = imgBitmap.getHeight();
        int imgWidth = imgBitmap.getWidth();

        float scale;
        int initX = 0;
        int initY = 0;

        if (defaultScale == ScaleImageView.DEFAULT_SCALE_FIT_INSIDE) {
            if (imgWidth > containerWidth) {
                scale = (float) containerWidth / imgWidth;
                float newHeight = imgHeight * scale;
                initY = (containerHeight - (int) newHeight) / 2;

                matrix.setScale(scale, scale);
                matrix.postTranslate(0, initY);
            } else {
                scale = (float) containerHeight / imgHeight;
                float newWidth = imgWidth * scale;
                initX = (containerWidth - (int) newWidth) / 2;

                matrix.setScale(scale, scale);
                matrix.postTranslate(initX, 0);
            }

            curX = initX;
            curY = initY;

            currentScale = scale;
            minScale = scale;
        } else {
            if (imgWidth > containerWidth) {
                initY = (containerHeight - (int) imgHeight) / 2;
                matrix.postTranslate(0, initY);
            } else {
                initX = (containerWidth - (int) imgWidth) / 2;
                matrix.postTranslate(initX, 0);
            }

            curX = initX;
            curY = initY;

            currentScale = 1.0f;
            minScale = 1.0f;
        }


        invalidate();
    }
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    if (imgBitmap != null && canvas != null) {
        if (drawCanvas == null)
            drawCanvas = new Canvas(imgBitmap);


        clipBounds = canvas.getClipBounds();

        canvas.drawBitmap(imgBitmap, matrix, background);

        canvas.concat(matrix);
        for (int i = 0; i < colors.size(); i++) {
            canvas.drawPath(paths.get(i), colors.get(i));
        }
        canvas.drawPath(drawPath, drawPaint);

    }
    canvas.restore();
    invalidate();
}

public void reDrawUndo() {
    System.out.println("paths.size" + paths.size());
    if (paths.size() > 0) {
        paths.remove(paths.size() - 1);
        colors.remove(colors.size() - 1);
        invalidate();
    }
}

//Checks and sets the target image x and y co-ordinates if out of bounds
private void checkImageConstraints() {
    if (imgBitmap == null) {
        return;
    }

    float[] mvals = new float[9];
    matrix.getValues(mvals);

    currentScale = mvals[0];

    if (currentScale < minScale) {
        float deltaScale = minScale / currentScale;
        float px = containerWidth / 2;
        float py = containerHeight / 2;
        matrix.postScale(deltaScale, deltaScale, px, py);
        invalidate();
    }

    matrix.getValues(mvals);
    currentScale = mvals[0];
    curX = mvals[2];
    curY = mvals[5];

    int rangeLimitX = containerWidth - (int) (imgBitmap.getWidth() * currentScale);
    int rangeLimitY = containerHeight - (int) (imgBitmap.getHeight() * currentScale);


    boolean toMoveX = false;
    boolean toMoveY = false;

    if (rangeLimitX < 0) {
        if (curX > 0) {
            targetX = 0;
            toMoveX = true;
        } else if (curX < rangeLimitX) {
            targetX = rangeLimitX;
            toMoveX = true;
        }
    } else {
        targetX = rangeLimitX / 2;
        toMoveX = true;
    }

    if (rangeLimitY < 0) {
        if (curY > 0) {
            targetY = 0;
            toMoveY = true;
        } else if (curY < rangeLimitY) {
            targetY = rangeLimitY;
            toMoveY = true;
        }
    } else {
        targetY = rangeLimitY / 2;
        toMoveY = true;
    }

    if (toMoveX == true || toMoveY == true) {
        if (toMoveY == false) {
            targetY = curY;
        }
        if (toMoveX == false) {
            targetX = curX;
        }

        //Disable touch event actions
        isAnimating = true;
        //Initialize timer
        mHandler.removeCallbacks(mUpdateImagePositionTask);
        mHandler.postDelayed(mUpdateImagePositionTask, 100);
    }
}


@Override
public boolean onTouchEvent(MotionEvent event) {

    matrix.getValues(mv);

    float touchX = (event.getX() * (1 / mv[4]) - (mv[2] / mv[4]));
    float touchY = (event.getY() * (1 / mv[4]) - (mv[5] / mv[4]));

    // Is drawing mode on?
    if (ScaleImageActivity.flag) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                drawPath.moveTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                drawPath.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                Paint newPaint = new Paint();
                newPaint.set(drawPaint);
                colors.add(newPaint);
                paths.add(drawPath);
                drawPath = new Path();
                drawPath.reset();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                System.out.println("bleh");
                break;
            default:
                return false;
        }
    } else {
        if (gestureDetector.onTouchEvent(event)) {
            return true;
        }

        if (isAnimating == true) {
            return true;
        }

        //Handle touch events here
        float[] mvals = new float[9];
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                if (isAnimating == false) {
                    savedMatrix.set(matrix);
                    start.set(event.getX(), event.getY());
                    mode = DRAG;
                }
                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    savedMatrix.set(matrix);
                    midPoint(mid, event);
                    mode = ZOOM;
                }
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;

                matrix.getValues(mvals);
                curX = mvals[2];
                curY = mvals[5];
                currentScale = mvals[0];

                if (isAnimating == false) {
                    checkImageConstraints();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (mode == DRAG && isAnimating == false) {
                    matrix.set(savedMatrix);
                    float diffX = event.getX() - start.x;
                    float diffY = event.getY() - start.y;

                    matrix.postTranslate(diffX, diffY);

                    matrix.getValues(mvals);
                    curX = mvals[2];
                    curY = mvals[5];
                    currentScale = mvals[0];
                } else if (mode == ZOOM && isAnimating == false) {
                    float newDist = spacing(event);
                    if (newDist > 10f) {
                        matrix.set(savedMatrix);
                        float scale = newDist / oldDist;
                        matrix.getValues(mvals);
                        currentScale = mvals[0];

                        if (currentScale * scale <= minScale) {
                            matrix.postScale(minScale / currentScale, minScale / currentScale, mid.x, mid.y);
                        } else if (currentScale * scale >= maxScale) {
                            matrix.postScale(maxScale / currentScale, maxScale / currentScale, mid.x, mid.y);
                        } else {
                            matrix.postScale(scale, scale, mid.x, mid.y);
                        }


                        matrix.getValues(mvals);
                        curX = mvals[2];
                        curY = mvals[5];
                        currentScale = mvals[0];
                    }
                }

                break;
        }
    }
    //Calculate the transformations and then invalidate
    invalidate();
    return true;
}

private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return (float) Math.sqrt(x * x + y * y);
}

private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
}


public void setImageBitmap(Bitmap b) {

    if (b != null) {

        imgBitmap = b;

        containerWidth = getWidth();
        containerHeight = getHeight();

        int imgHeight = imgBitmap.getHeight();
        int imgWidth = imgBitmap.getWidth();

        float scale;
        int initX = 0;
        int initY = 0;

        matrix.reset();

        if (defaultScale == ScaleImageView.DEFAULT_SCALE_FIT_INSIDE) {
            if (imgWidth > containerWidth) {
                scale = (float) containerWidth / imgWidth;
                float newHeight = imgHeight * scale;
                initY = (containerHeight - (int) newHeight) / 2;

                matrix.setScale(scale, scale);
                matrix.postTranslate(0, initY);
            } else {
                scale = (float) containerHeight / imgHeight;
                float newWidth = imgWidth * scale;
                initX = (containerWidth - (int) newWidth) / 2;

                matrix.setScale(scale, scale);
                matrix.postTranslate(initX, 0);
            }

            curX = initX;
            curY = initY;

            currentScale = scale;
            minScale = scale;
        } else {
            if (imgWidth > containerWidth) {
                initX = 0;
                if (imgHeight > containerHeight) {
                    initY = 0;
                } else {
                    initY = (containerHeight - (int) imgHeight) / 2;
                }

                matrix.postTranslate(0, initY);
            } else {
                initX = (containerWidth - (int) imgWidth) / 2;
                if (imgHeight > containerHeight) {
                    initY = 0;
                } else {
                    initY = (containerHeight - (int) imgHeight) / 2;
                }
                matrix.postTranslate(initX, 0);
            }

            curX = initX;
            curY = initY;

            currentScale = 1.0f;
            minScale = 1.0f;
        }
     }

        invalidate();

                         }


private Runnable mUpdateImagePositionTask = new Runnable() {
    public void run() {
        float[] mvals;

        if (Math.abs(targetX - curX) < 5 && Math.abs(targetY - curY) < 5) {
            isAnimating = false;
            mHandler.removeCallbacks(mUpdateImagePositionTask);

            mvals = new float[9];
            matrix.getValues(mvals);

            currentScale = mvals[0];
            curX = mvals[2];
            curY = mvals[5];

            //Set the image parameters and invalidate display
            float diffX = (targetX - curX);
            float diffY = (targetY - curY);

            matrix.postTranslate(diffX, diffY);
        } else {
            isAnimating = true;
            mvals = new float[9];
            matrix.getValues(mvals);

            currentScale = mvals[0];
            curX = mvals[2];
            curY = mvals[5];

            //Set the image parameters and invalidate display
            float diffX = (targetX - curX) * 0.3f;
            float diffY = (targetY - curY) * 0.3f;

            matrix.postTranslate(diffX, diffY);
            mHandler.postDelayed(this, 25);
        }

        invalidate();
    }
};

private Runnable mUpdateImageScale = new Runnable() {
    public void run() {
        float transitionalRatio = targetScale / currentScale;
        float dx;
        if (Math.abs(transitionalRatio - 1) > 0.05) {
            isAnimating = true;
            if (targetScale > currentScale) {
                dx = transitionalRatio - 1;
                scaleChange = 1 + dx * 0.2f;

                currentScale *= scaleChange;

                if (currentScale > targetScale) {
                    currentScale = currentScale / scaleChange;
                    scaleChange = 1;
                }
            } else {
                dx = 1 - transitionalRatio;
                scaleChange = 1 - dx * 0.5f;
                currentScale *= scaleChange;

                if (currentScale < targetScale) {
                    currentScale = currentScale / scaleChange;
                    scaleChange = 1;
                }
            }


            if (scaleChange != 1) {
                matrix.postScale(scaleChange, scaleChange, targetScaleX, targetScaleY);
                mHandler.postDelayed(mUpdateImageScale, 15);
                invalidate();
            } else {
                isAnimating = false;
                scaleChange = 1;
                matrix.postScale(targetScale / currentScale, targetScale / currentScale, targetScaleX, targetScaleY);
                currentScale = targetScale;
                mHandler.removeCallbacks(mUpdateImageScale);
                invalidate();
                checkImageConstraints();
            }
        } else {
            isAnimating = false;
            scaleChange = 1;
            matrix.postScale(targetScale / currentScale, targetScale / currentScale, targetScaleX, targetScaleY);
            currentScale = targetScale;
            mHandler.removeCallbacks(mUpdateImageScale);
            invalidate();
            checkImageConstraints();
        }
    }
};

class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onDoubleTap(MotionEvent event) {
        if (isAnimating == true) {
            return true;
        }

        scaleChange = 1;
        isAnimating = true;
        targetScaleX = event.getX();
        targetScaleY = event.getY();

        if (Math.abs(currentScale - maxScale) > 0.1) {
            targetScale = maxScale;
        } else {
            targetScale = minScale;
        }
        targetRatio = targetScale / currentScale;
        mHandler.removeCallbacks(mUpdateImageScale);
        mHandler.post(mUpdateImageScale);
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return super.onFling(e1, e2, velocityX, velocityY);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }
}

     }

ScaleImageActivity.java

public class ScaleImageActivity extends Activity implements OnClickListener {

private Button btndraw, btnzoom;
private Bitmap bmp , alteredBitmap;
private ScaleImageView imageview;
public static boolean flag = true;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.batata);

    initwidget();


}

private void initwidget() {

    imageview = (ScaleImageView) findViewById(R.id.image);
    btndraw = (Button) findViewById(R.id.activity_main_zoom_draw);
    btnzoom = (Button) findViewById(R.id.activity_main_zoom_zoom);


    btndraw.setOnClickListener(this);
    btnzoom.setOnClickListener(this);

    Intent choosePictureIntent = new Intent(
            Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(choosePictureIntent, 0);

}

@Override
public void onClick(View arg0) {
    // TODO Auto-generated method stub
    if (btndraw.equals(arg0))
        flag = true;

     else if (btnzoom.equals(arg0))
        flag = false;

}

protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    if (resultCode == RESULT_OK) {

        Uri imageFileUri = intent.getData();

        try {

            BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
            bmpFactoryOptions.inJustDecodeBounds = true;
          bmp = BitmapFactory
                    .decodeStream(
                            getContentResolver().openInputStream(
                                    imageFileUri), null, bmpFactoryOptions);

            bmpFactoryOptions.inJustDecodeBounds = false;
            bmp = BitmapFactory
                    .decodeStream(
                            getContentResolver().openInputStream(
                                    imageFileUri), null, bmpFactoryOptions);



            alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getWidth(), bmp.getConfig());

            imageview.setImageBitmap(alteredBitmap);


        }

        catch (Exception e) {
            Log.v("ERROR", e.toString());

        }

    }

}

 }

.XML布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/activity_main_zoom_zoom"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Zoom" />

        <Button
            android:id="@+id/activity_main_zoom_draw"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Draw" />

    </LinearLayout>


   <julien.pc.drawing.ScaleImageView
       android:id="@+id/image"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content" />

</LinearLayout>

0 个答案:

没有答案