使用图像无法正确缩放的绘制视图缩放:Android

Posted

技术标签:

【中文标题】使用图像无法正确缩放的绘制视图缩放:Android【英文标题】:Paint View Zoom with Image not properly zoom : Android 【发布时间】:2013-05-16 07:37:08 【问题描述】:

我使用画布来缩放带有图像的绘制视图,包括使用 setImageMatrix()。如下所示,用于缩放和画线的类。但是出现了问题,那就是整个屏幕变成了放大/缩小,然后当我点击绘画按钮时,我将一个布尔值传递为 false,它在手指触摸时画线。但在画线之后在图像上,我想用这条画线再次开始捏缩放,然后我也可以用画图放大/缩小,但它没有以正确的方式改变画图的 x-y。所以如果有人知道这个问题,请回复。

public class PaintScreen extends Activity 

    Context mContext;
    private Paint mPaint;
    MaskFilter mEmboss;
    MaskFilter mBlur;
    private LinearLayout mPaintBaseLayout;
    private PaintView mPaintView;

    // These matrices will be used to move and zoom image
    Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();
    Matrix savedMatrix2 = new Matrix();

    private int WIDTH = 0;
    private int HEIGHT = 1;

    // We can be in one of these 3 states
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int POINT2 = 2;
    static final int ZOOM = 3;
    int mode = NONE;

    // Remember some things for zooming
    PointF start = new PointF();
    PointF mid = new PointF();
    float oldDist = 1f;
    float newDist;
    float distanceOffset = 50f;
    float minOffset = 50f;
    float maxOffset = 10000f;
    private boolean falg = true;
    private int startval = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_main);

        this.initialize();

        this.PaintSet();

        Button button = (Button) findViewById(R.id.btnzoom);
        button.setOnClickListener(new OnClickListener() 
            @Override
            public void onClick(View v) 
                if (falg) 
                    getFlag(false);
                 else 
                    getFlag(true);
                
            
        );

        Button btnset = (Button) findViewById(R.id.btnset);
        btnset.setOnClickListener(new OnClickListener() 
            @Override
            public void onClick(View v) 
                startval = 1;
            
        );
    

    private void initialize() 
        mPaintBaseLayout = (LinearLayout) findViewById(R.id.paint_paint_base_layout);

        mContext = this;
        mPaint = new Paint();
        mPaintView = new PaintView(mContext);
        mPaintView.setBackgroundColor(Color.TRANSPARENT);
        mPaintBaseLayout.addView(mPaintView, new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        mPaintBaseLayout.setBackgroundColor(Color.TRANSPARENT);

        mPaintView.setScaleType(ScaleType.MATRIX);
        mPaintView.setMPaint(mPaint);
        Bitmap bm = BitmapFactory
                .decodeResource(getResources(), R.drawable.nat);

        mPaintView.setImageBitmap(bm);

        mPaintView.setOnTouchListener(new OnTouchListener() 

            @Override
            public boolean onTouch(View v, MotionEvent event) 
                PaintView view = (PaintView) v;

                switch (event.getAction() & MotionEvent.ACTION_MASK) 
                case MotionEvent.ACTION_DOWN:
                    if (falg) 
                        savedMatrix.set(matrix);
                        start.set(event.getX(), event.getY());
                        mode = DRAG;
                     else 
                        view.onTouchEvent(event);
                    
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    if (falg) 
                        oldDist = spacing(event);
                        if (oldDist > 10f) 
                            start.set(event.getX(), event.getY());
                            savedMatrix.set(matrix);
                            midPoint(mid, event);
//                           mode = POINT2;
                            mode = ZOOM;
                        
                    
                    break;
                case MotionEvent.ACTION_UP:
                    if (falg) 
                        mode = NONE;
                        distanceOffset = minOffset;
                    
                case MotionEvent.ACTION_POINTER_UP:
                    if (falg) 
                        mode = NONE;
                        distanceOffset = minOffset;
                    
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (falg) 
                        if (mode == POINT2) 
                            newDist = spacing(event);
                            if (newDist - oldDist > 5f
                                    || newDist - oldDist < -5f) 
                                mode = ZOOM;
                             else 
                                start.set(event.getX(), event.getY());
                                mode = DRAG;

                            
                         else if (mode == DRAG) 
                            matrix.set(savedMatrix);
                            matrix.postTranslate(event.getX() - start.x,
                                    event.getY() - start.y);

                         else if (mode == ZOOM) 
                            newDist = spacing(event);
                            if (newDist > 10f) 
                                matrix.set(savedMatrix);
                                float scale = newDist / oldDist;
                                matrix.postScale(scale, scale, mid.x, mid.y);
                            
                        
                     else 
                        view.onTouchEvent(event);
                    
                    break;
                

//              if (startval == 1) 
                    view.cMatrix(matrix);
//              
                view.setImageMatrix(matrix);
                matrixTurning(matrix, view);
                return true;
            
        );
    

    public boolean getFlag(boolean b) 
        return falg = b;
    

    /** Determine the space between the first two fingers */
    private static float spacing(MotionEvent event) 
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    

    /** Calculate the mid point of the first two fingers */
    private static 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);
    

    private void matrixTurning(Matrix matrix, ImageView view) 

        float[] value = new float[9];
        matrix.getValues(value);
        float[] savedValue = new float[9];
        savedMatrix2.getValues(savedValue);

        // view size
        int width = view.getWidth();
        int height = view.getHeight();

        // image size
        Drawable d = view.getDrawable();
        if (d == null)
            return;
        int imageWidth = d.getIntrinsicWidth();
        int imageHeight = d.getIntrinsicHeight();
        int scaleWidth = (int) (imageWidth * value[0]);
        int scaleHeight = (int) (imageHeight * value[0]);

        if (value[2] < width - scaleWidth)
            value[2] = width - scaleWidth;
        if (value[5] < height - scaleHeight)
            value[5] = height - scaleHeight;
        if (value[2] > 0)
            value[2] = 0;
        if (value[5] > 0)
            value[5] = 0;

        if (value[0] > 10 || value[4] > 10) 
            value[0] = savedValue[0];
            value[4] = savedValue[4];
            value[2] = savedValue[2];
            value[5] = savedValue[5];
        

        if (imageWidth > width || imageHeight > height) 

            if (scaleWidth < width && scaleHeight < height) 
                int target = WIDTH;

                if (imageWidth < imageHeight)
                    target = HEIGHT;

                if (target == WIDTH)
                    value[0] = value[4] = (float) width / imageWidth;
                if (target == HEIGHT)
                    value[0] = value[4] = (float) height / imageHeight;

                scaleWidth = (int) (imageWidth * value[0]);
                scaleHeight = (int) (imageHeight * value[4]);

                if (scaleWidth == width)
                    value[0] = value[4] = (float) width / imageWidth;
                if (scaleHeight == height)
                    value[0] = value[4] = (float) height / imageHeight;
            

         else 
            if (value[0] < 1)
                value[0] = 1;
            if (value[4] < 1)
                value[4] = 1;
        

        scaleWidth = (int) (imageWidth * value[0]);
        scaleHeight = (int) (imageHeight * value[4]);

        if (scaleWidth < width) 
            value[2] = (float) width / 2 - (float) scaleWidth / 2;
        
        if (scaleHeight < height) 
            value[5] = (float) height / 2 - (float) scaleHeight / 2;
        

        matrix.setValues(value);
        savedMatrix2.set(matrix);

    

    public void PaintSet() 

        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0xFFFF0000);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(10);

        // getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
        mEmboss = new EmbossMaskFilter(new float[]  1, 1, 1 , 0.4f, 6, 3.5f);
        mBlur = new BlurMaskFilter(24, BlurMaskFilter.Blur.NORMAL);
    

    public void colorChanged(int color) 
        mPaint.setColor(color);
    


class PaintView extends ImageView 

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mBitmapPaint;

    // onDraw
    private Paint mPaint;

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

    public PaintView(Context context) 
        this(context, null);
    

    public PaintView(Context context, AttributeSet attrs) 
        super(context, attrs);

        mBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);

    

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
        super.onSizeChanged(w, h, oldw, oldh);
    

    @Override
    protected void onDraw(Canvas canvas) 
        // canvas.drawColor(0xFFAAAAAA);
        super.onDraw(canvas);
        mCanvas = canvas;
        // canvas = mCanvas;
        Matrix localMatrix = new Matrix();
        localMatrix.setRectToRect(
                new RectF(0.0F, 0.0F, mBitmap.getWidth(), mBitmap
                        .getHeight()),
                new RectF(0.0F, 0.0F, this.mCanvas.getWidth(),
                        this.mCanvas.getHeight()),
                Matrix.ScaleToFit.CENTER);
        canvas.drawBitmap(mBitmap, localMatrix, mBitmapPaint);
//      canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
//      canvas.drawBitmap(mBitmap, PaintScreen.matrix, mBitmapPaint);
        canvas.drawPath(mPath, mPaint);

    

    public void setMPaint(Paint paint) 
        mPaint = paint;
    

    private void touchStart(float x, float y) 
        // mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    

    private void touchMove(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 touchUp() 
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    

    @Override
    public boolean onTouchEvent(MotionEvent event) 
        float x = event.getX();
        float y = event.getY();

        Log.d("PaintView", "ev ->" + event.getAction());

        switch (event.getAction()) 
        case MotionEvent.ACTION_DOWN:
            touchStart(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touchMove(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touchUp();
            invalidate();
            break;
        
        return true;
    

    public void cMatrix(Matrix matrix) 
        mCanvas.setMatrix(matrix);
    


【问题讨论】:

【参考方案1】:

试试这样的,但我不确定

     @Override
  public boolean onTouch(View v, MotionEvent event) 
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
dumpEvent(event);
// Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) 
case MotionEvent.ACTION_DOWN:
    savedMatrix.set(matrix);
    start.set(event.getX(), event.getY());
    Log.d(TAG, "mode=DRAG");
    mode = DRAG;
    break;
case MotionEvent.ACTION_POINTER_DOWN:
    oldDist = spacing(event);
    Log.d(TAG, "oldDist=" + oldDist);
    if (oldDist > 10f) 
        savedMatrix.set(matrix);
        midPoint(mid, event);
        mode = ZOOM;
        Log.d(TAG, "mode=ZOOM");
    
    break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
    mode = NONE;
    Log.d(TAG, "mode=NONE");
    break;
case MotionEvent.ACTION_MOVE:
    if (mode == DRAG) 
        // ...
        matrix.set(savedMatrix);
        matrix.postTranslate(event.getX() - start.x, event.getY()
                - start.y);
     else if (mode == ZOOM) 
        float newDist = spacing(event);
        Log.d(TAG, "newDist=" + newDist);
        if (newDist > 10f) 
            matrix.set(savedMatrix);
            float scale = newDist / oldDist;
            matrix.postScale(scale, scale, mid.x, mid.y);
        
    
    break;

view.setImageMatrix(matrix);
return true;

 private void dumpEvent(MotionEvent event) 
String names[] =  "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
        "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" ;
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_").append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
        || actionCode == MotionEvent.ACTION_POINTER_UP) 
    sb.append("(pid ").append(
            action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
    sb.append(")");

sb.append("[");
for (int i = 0; i < event.getPointerCount(); i++) 
    sb.append("#").append(i);
    sb.append("(pid ").append(event.getPointerId(i));
    sb.append(")=").append((int) event.getX(i));
    sb.append(",").append((int) event.getY(i));
    if (i + 1 < event.getPointerCount())
        sb.append(";");

sb.append("]");
Log.d(TAG, sb.toString());

 /** Determine the space between the first two fingers */
  private float spacing(MotionEvent event) 
 float x = event.getX(0) - event.getX(1);
 float y = event.getY(0) - event.getY(1);
 return FloatMath.sqrt(x * x + y * y);
 
/** Calculate the mid point of the first two fingers */
  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);

并且不要忘记将scaleType属性设置为imageview标签的矩阵,例如,

       <ImageView
        android:id="@+id/imageEnhance"
        android:layout_
        android:layout_
        android:layout_gravity="center_horizontal"
        android:layout_marginBottom="15dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="15dp"
        android:background="@drawable/enhanceimageframe"
        android:scaleType="matrix" >
    </ImageView>

并且使用的变量是,

     // These matrices will be used to move and zoom image
   Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();
      // 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;
      // Remember some things for zooming
    PointF start = new PointF();
    PointF mid = new PointF();
    float oldDist = 1f;
    String savedItemClicked;

【讨论】:

你想在你的视图中绘画【参考方案2】:

图像缩放并在图像上绘画

imageView.setOnTouchListener(new OnTouchListener() 
            @Override
            public boolean onTouch(View v, MotionEvent event) 
                ImageView view = (ImageView) v;

                switch (event.getAction() & MotionEvent.ACTION_MASK) 
                case MotionEvent.ACTION_DOWN:
                    savedMatrix.set(matrix1);
                    start.set(event.getX(), event.getY());
                    mode = DRAG;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    oldDist = spacing(event);
                    if (oldDist > 10f) 
                        start.set(event.getX(), event.getY());
                        savedMatrix.set(matrix1);
                        midPoint(mid, event);
                        // mode = POINT2;
                        mode = ZOOM;
                    
                    break;
                case MotionEvent.ACTION_UP:
                    mode = NONE;
                    distanceOffset = minOffset;
                case MotionEvent.ACTION_POINTER_UP:
                    mode = NONE;
                    distanceOffset = minOffset;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == POINT2) 
                        newDist = spacing(event);
                        if (newDist - oldDist > 5f
                                || newDist - oldDist < -5f) 
                            mode = ZOOM;
                         else 
                            start.set(event.getX(), event.getY());
                            mode = DRAG;
                        
                     else if (mode == DRAG) 
                        matrix1.set(savedMatrix);
                        matrix1.postTranslate(event.getX() - start.x,
                                event.getY() - start.y);
                     else if (mode == ZOOM) 
                        newDist = spacing(event);
                        if (newDist > 10f) 
                            matrix1.set(savedMatrix);
                            float scale = newDist / oldDist;
                            matrix1.postScale(scale, scale, mid.x,
                                    mid.y);
                            finalscale = scale;
                        
                    
                    break;
                

                view.setImageMatrix(matrix1);
//              matrixTurning(matrix1, view);
                return true; // indicate event was handled
            
        );
    



mPaintView.setOnTouchListener(new OnTouchListener() 

            @Override
            public boolean onTouch(View v, MotionEvent event) 
                PaintView view = (PaintView) v;
                view.setScaleType(ImageView.ScaleType.MATRIX);
                switch (event.getAction() & MotionEvent.ACTION_MASK) 
                case MotionEvent.ACTION_DOWN:
                    if (falg) 
                        savedMatrix.set(matrix);
                        start.set(event.getX(), event.getY());
                        mode = DRAG;
                     else 
                        view.onTouchEvent(event);
                    
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    if (falg) 
                        oldDist = spacing(event);
                        if (oldDist > 10f) 
                            start.set(event.getX(), event.getY());
                            savedMatrix.set(matrix);
                            midPoint(mid, event);
                            mode = ZOOM;
                        
                    
                    break;
                case MotionEvent.ACTION_UP:
                    if (falg) 
                        mode = NONE;
                        distanceOffset = minOffset;
                    
                case MotionEvent.ACTION_POINTER_UP:
                    if (falg) 
                        mode = NONE;
                        distanceOffset = minOffset;
                    
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (falg) 
                        if (mode == POINT2) 
                            newDist = spacing(event);
                            if (newDist - oldDist > 5f
                                    || newDist - oldDist < -5f) 
                                mode = ZOOM;
                             else 
                                start.set(event.getX(), event.getY());
                                mode = DRAG;
                            
                         else if (mode == DRAG) 
                            matrix.set(savedMatrix);
                            matrix.postTranslate(event.getX() - start.x,
                                    event.getY() - start.y);
                         else if (mode == ZOOM) 
                            newDist = spacing(event);
                            if (newDist > 10f) 
                                matrix.set(savedMatrix);
                                float scale = newDist / oldDist;
                                matrix.postScale(scale, scale, mid.x, mid.y);
                                finalscale = scale;
                            
                        
                     else 
                        view.onTouchEvent(event);
                    
                    break;
                

                limitZoom(matrix);
                view.setImageMatrix(matrix);

                matrixTurning(matrix, view);
                RectF r = new RectF();
                matrix.mapRect(r);
                scaledImageOffsetX = r.left;
                scaledImageOffsetY = r.top;

                return true;
            
        );
    


    private void limitZoom(Matrix m) 

        float[] values = new float[9];
        m.getValues(values);
        float scaleX = values[Matrix.MSCALE_X];
        float scaleY = values[Matrix.MSCALE_Y];
        if(scaleX > MAX_ZOOM) 
            scaleX = MAX_ZOOM;
         else if(scaleX < MIN_ZOOM) 
            scaleX = MIN_ZOOM;
        

        if(scaleY > MAX_ZOOM) 
            scaleY = MAX_ZOOM;
         else if(scaleY < MIN_ZOOM) 
            scaleY = MIN_ZOOM;
        

        values[Matrix.MSCALE_X] = scaleX;
        values[Matrix.MSCALE_Y] = scaleY; 
        m.setValues(values);
    

    public boolean getFlag(boolean b) 
        return falg = b;
    

PaintView.class

    class PaintView extends ImageView 

private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;

// onDraw
private Paint mPaint;

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

public PaintView(Context context) 
    this(context, null);


public PaintView(Context context, AttributeSet attrs) 
    super(context, attrs);

    mBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
    mPath = new Path();
    mBitmapPaint = new Paint(Paint.DITHER_FLAG);



@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) 
    super.onSizeChanged(w, h, oldw, oldh);


@Override
protected void onDraw(Canvas canvas) 
    // canvas.drawColor(0xFFAAAAAA);
    super.onDraw(canvas);
    mCanvas = canvas;
    // canvas = mCanvas;
     canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    // canvas.drawBitmap(mBitmap, PaintScreen.matrix, mBitmapPaint);
    canvas.drawPath(mPath, mPaint);



public void clear() 
    mPaint.reset();
    // invalidate();


public void setMPaint(Paint paint) 
    mPaint = paint;


private void touchStart(float x, float y) 
    // mPath.reset();
    mPath.moveTo(x, y);
    mX = x;
    mY = y;


private void touchMove(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 touchUp() 
    mPath.lineTo(mX, mY);
    // commit the path to our offscreen
    mCanvas.drawPath(mPath, mPaint);
    // kill this so we don't double draw
    mPath.reset();


@Override
public boolean onTouchEvent(MotionEvent event) 
    float x = event.getX();
    float y = event.getY();

    Log.d("PaintView", "ev ->" + event.getAction());

    switch (event.getAction()) 
    case MotionEvent.ACTION_DOWN:
        touchStart(x, y);
        invalidate();
        break;
    case MotionEvent.ACTION_MOVE:
        touchMove(x, y);
        invalidate();
        break;
    case MotionEvent.ACTION_UP:
        touchUp();
        invalidate();
        break;
    
    return true;


public void cMatrix(Matrix matrix) 
    mCanvas.setMatrix(matrix);


【讨论】:

以上是关于使用图像无法正确缩放的绘制视图缩放:Android的主要内容,如果未能解决你的问题,请参考以下文章

添加背景图像时,Xamarin android网格无法正确缩放单元格

在 ios 的滚动视图中绘制缩放的图像视图?

SwiftUI - 缩放、缩放和裁剪图像

Android在画布上操纵图像 - 使用触摸,移动,放大/缩小,缩放

Android 刷卡使用 SwipeFlingAdapterView 库缩放图像视图

如何忽略缩放图像视图 Swift 3