2014-10-06 83 views
1

我正在研究一种可以在其上绘制线条的自定义图像视图,问题是绘图区域大小与位图大小不完全相同。在android中的图片上绘制

例如,在其他应用程序,它看起来像:

enter image description here

然而,在我的应用程序,它看起来像

enter image description here

这是我的计划,这似乎位图不适合画布。感谢您的帮助

public class DrawingView extends View { 

    //drawing path 
    private Path drawPath; 
    //drawing and canvas paint 
    private Paint drawPaint, canvasPaint; 
    //initial color 
    private int paintColor = 0xFF660000; 
    //canvas 
    private Canvas drawCanvas; 
    //canvas bitmap 
    private Bitmap canvasBitmap; 


    public DrawingView(Context context, AttributeSet attrs){ 
     super(context, attrs); 
     setupDrawing(); 
    } 

    //setup drawing 
    private void setupDrawing(){ 

     //prepare for drawing and setup paint stroke properties 
     drawPath = new Path(); 
     drawPaint = new Paint(); 
     drawPaint.setColor(paintColor); 
     drawPaint.setAntiAlias(true); 
     drawPaint.setStrokeWidth(15.0f); 
     drawPaint.setStyle(Paint.Style.STROKE); 
     drawPaint.setStrokeJoin(Paint.Join.ROUND); 
     drawPaint.setStrokeCap(Paint.Cap.ROUND); 
     canvasPaint = new Paint(Paint.DITHER_FLAG); 
    } 

    //size assigned to view 
    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     super.onSizeChanged(w, h, oldw, oldh); 
     canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
     drawCanvas = new Canvas(canvasBitmap); 
    } 

    //draw the view - will be called after touch event 
    @Override 
    protected void onDraw(Canvas canvas) { 
     canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), 0, 0, canvasPaint); 
     canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); 
     canvas.drawPath(drawPath, drawPaint); 
    } 

    //register user touches as drawing action 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     float touchX = event.getX(); 
     float touchY = event.getY(); 
     //respond to down, move and up events 
     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: 
      drawPath.lineTo(touchX, touchY); 
      drawCanvas.drawPath(drawPath, drawPaint); 
      drawPath.reset(); 
      break; 
     default: 
      return false; 
     } 
     //redraw 
     invalidate(); 
     return true; 

    } 

    //update color 
    public void setColor(String newColor){ 
     invalidate(); 
     paintColor = Color.parseColor(newColor); 
     drawPaint.setColor(paintColor); 
    } 

    //start new drawing 
    public void startNew(){ 
     drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR); 
     invalidate(); 
    } 
} 

而且我发现类似的教程代码,问题是,触摸事件有缺陷,它在操作栏,其余的UI元素计数所以触摸是怪异。推荐给看看

http://www.java2s.com/Code/Android/2D-Graphics/DrawonPictureandsave.htm

因此,本课题的目标,是

1)抽取能够像解决

2)变焦能力和泛能(可以使用库)(当活性放大,缩小,不活动时变焦,画出)

可以引用截图1为理念

由于一个很多帮助

+0

检查这个http://stackoverflow.com/questions/15704205/how-to-draw-line-on-imageview-along-with-finger-in-android如果它有帮助 – Raghunandan 2015-01-30 09:19:23

+0

请看看我的答案@ user782104 – sandeepmaaram 2015-01-31 11:55:38

+0

“问题在于触摸事件有问题”你真的认为什么错误? – pskink 2015-02-01 20:07:10

回答

6

您可以通过创建自己的ImageView来避免统计其他UI项目的坐标。试试这个代码为Activity

public class DrawOnBitmapActivity extends Activity implements OnClickListener 
    { 

DrawableImageView choosenImageView; 
Button choosePicture; 
Button savePicture; 

Bitmap bmp; 
Bitmap alteredBitmap; 

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

    choosenImageView = (DrawableImageView) this.findViewById(R.id.ChoosenImageView); 
    choosePicture = (Button) this.findViewById(R.id.ChoosePictureButton); 
    savePicture = (Button) this.findViewById(R.id.SavePictureButton); 

    savePicture.setOnClickListener(this); 
    choosePicture.setOnClickListener(this); 
} 

public void onClick(View v) 
{ 
    if (v == choosePicture) 
    { 
     Intent choosePictureIntent = new Intent(
       Intent.ACTION_PICK, 
       android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 
     startActivityForResult(choosePictureIntent, 0); 
    } 
    else if (v == savePicture) 
    { 
     if (alteredBitmap != null) 
     { 
      ContentValues contentValues = new ContentValues(3); 
      contentValues.put(Media.DISPLAY_NAME, "Draw On Me"); 

      Uri imageFileUri = getContentResolver().insert(
        Media.EXTERNAL_CONTENT_URI, contentValues); 
      try { 
       OutputStream imageFileOS = getContentResolver() 
         .openOutputStream(imageFileUri); 
       alteredBitmap 
         .compress(CompressFormat.JPEG, 90, imageFileOS); 
       Toast t = Toast 
         .makeText(this, "Saved!", Toast.LENGTH_SHORT); 
       t.show(); 

      } catch (Exception e) { 
       Log.v("EXCEPTION", e.getMessage()); 
      } 
     } 
    } 
} 

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.getHeight(), bmp.getConfig()); 

      choosenImageView.setNewImage(alteredBitmap, bmp); 
     } 
     catch (Exception e) { 
      Log.v("ERROR", e.toString()); 
     } 
    } 
} 
} 

你必须改变轻微activity_main布局:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
    <Button 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:text="Choose Picture" android:id="@+id/ChoosePictureButton"/> 
    <ru.pristalovpavel.drawonimage.DrawableImageView android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:id="@+id/ChoosenImageView"> 
    </ru.pristalovpavel.drawonimage.DrawableImageView> 
    <Button 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:text="Save Picture" android:id="@+id/SavePictureButton"/> 
</LinearLayout> 

和自定义ImageView

public class DrawableImageView extends ImageView implements OnTouchListener 
{ 
    float downx = 0; 
    float downy = 0; 
    float upx = 0; 
    float upy = 0; 

    Canvas canvas; 
    Paint paint; 
    Matrix matrix; 

    public DrawableImageView(Context context) 
    { 
     super(context); 
     setOnTouchListener(this); 
    } 

    public DrawableImageView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
     setOnTouchListener(this); 
    } 

    public DrawableImageView(Context context, AttributeSet attrs, 
      int defStyleAttr) 
    { 
     super(context, attrs, defStyleAttr); 
     setOnTouchListener(this); 
    } 

    public void setNewImage(Bitmap alteredBitmap, Bitmap bmp) 
    { 
     canvas = new Canvas(alteredBitmap); 
     paint = new Paint(); 
     paint.setColor(Color.GREEN); 
     paint.setStrokeWidth(5); 
     matrix = new Matrix(); 
     canvas.drawBitmap(bmp, matrix, paint); 

     setImageBitmap(alteredBitmap); 
    } 

    @Override 
    public boolean onTouch(View v, MotionEvent event) 
    { 
     int action = event.getAction(); 

     switch (action) 
     { 
     case MotionEvent.ACTION_DOWN: 
      downx = getPointerCoords(event)[0];//event.getX(); 
      downy = getPointerCoords(event)[1];//event.getY(); 
      break; 
     case MotionEvent.ACTION_MOVE: 
      upx = getPointerCoords(event)[0];//event.getX(); 
      upy = getPointerCoords(event)[1];//event.getY(); 
      canvas.drawLine(downx, downy, upx, upy, paint); 
      invalidate(); 
      downx = upx; 
      downy = upy; 
      break; 
     case MotionEvent.ACTION_UP: 
      upx = getPointerCoords(event)[0];//event.getX(); 
      upy = getPointerCoords(event)[1];//event.getY(); 
      canvas.drawLine(downx, downy, upx, upy, paint); 
      invalidate(); 
      break; 
     case MotionEvent.ACTION_CANCEL: 
      break; 
     default: 
      break; 
     } 
     return true; 
    } 

    final float[] getPointerCoords(MotionEvent e) 
    { 
     final int index = e.getActionIndex(); 
     final float[] coords = new float[] { e.getX(index), e.getY(index) }; 
     Matrix matrix = new Matrix(); 
     getImageMatrix().invert(matrix); 
     matrix.postTranslate(getScrollX(), getScrollY()); 
     matrix.mapPoints(coords); 
     return coords; 
    } 
} 

在Eclipse项目的所有源代码:link

UPDATE:

DrawableImageView的新源代码!

更多的信息在my blog

+0

非常感谢,尝试导入源代码,但似乎绘图区域不适合图片,你会介意使用一些大图片并进行测试 – user782104 2015-01-29 06:42:17

+1

我的错!我已经更新了答案。只需刷新'DrawableImageView'。至于它它的工作原理) – anil 2015-01-29 08:11:31

+0

@ user782104在这个缩放功能不存在 – sandeepmaaram 2015-02-02 09:08:43

0

请看看

activity_main.xml中

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
tools:context=".MainActivity" > 
<Button 
    android:id="@+id/enable_zoom" 
    android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:text="disable zoom"/> 

<com.rbt.zoomdraw.CustomImageView 
    android:id="@+id/zoom_iv" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:src="@drawable/ic_launcher" 
    android:layout_below="@+id/enable_zoom" /> 

<com.rbt.zoomdraw.DrawableView 
    android:id="@+id/drawble_view" 
    android:layout_width="wrap_content" 
    android:layout_height="match_parent" 
    android:layout_alignBottom="@+id/zoom_iv" 
    android:layout_alignTop="@+id/zoom_iv" /> 

MainActivity。java的

public class MainActivity extends Activity implements OnClickListener { 

private Button enableZoomBtn; 
private DrawableView drawbleView; 
private CustomImageView touchImageView; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    drawbleView = (DrawableView) findViewById(R.id.drawble_view); 
    enableZoomBtn = (Button) findViewById(R.id.enable_zoom); 
    touchImageView = (CustomImageView) findViewById(R.id.zoom_iv); 
    enableZoomBtn.setOnClickListener(this); 
    drawbleView.setDrawingEnabled(false); 
} 
@Override 
public void onClick(View v) { 
    int id = v.getId(); 
    switch (id) { 
    case R.id.enable_zoom: 
     if(enableZoomBtn.getText().equals("disable zoom")){ 
      touchImageView.setZoomEnable(false); 
      drawbleView.setDrawingEnabled(true); 
      enableZoomBtn.setText("enable zoom"); 
     } else{ 
      touchImageView.setZoomEnable(true); 
      drawbleView.setDrawingEnabled(false); 
      enableZoomBtn.setText("disable zoom"); 
     } 
     break; 

    default: 
     break; 
    } 
    } 
} 

DrawableView.java

public class DrawableView extends View { 
public int width; 
public int height; 
private boolean isEditable; 
private Path drawPath; 
private Paint drawPaint; 
private Paint canvasPaint; 
private Canvas drawCanvas; 
private Bitmap canvasBitmap; 
private int paintColor = Color.RED; 
public DrawableView(Context context) { 
    super(context); 
} 
public DrawableView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    this.canvasPaint = new Paint(Paint.DITHER_FLAG); 
    setupDrawing(); 
} 
public DrawableView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
} 
@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 
    this.height = h; 
    this.width = w; 
    canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    drawCanvas = new Canvas(canvasBitmap); 
} 
private void setupDrawing() { 
    drawPath = new Path(); 
    drawPaint = new Paint(); 
    drawPaint.setColor(paintColor); 
    drawPaint.setAntiAlias(true); 
    drawPaint.setDither(true); 
    drawPaint.setStyle(Paint.Style.STROKE); 
    drawPaint.setStrokeJoin(Paint.Join.ROUND); 
    drawPaint.setStrokeCap(Paint.Cap.ROUND); 
    drawPaint.setStrokeWidth(10); 
} 
public void setDrawingEnabled(boolean isEditable){ 
    this.isEditable = isEditable; 
} 
@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); 
    canvas.drawPath(drawPath, drawPaint); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    if(isEditable){ 
     float touchX = event.getX(); 
     float touchY = event.getY(); 
     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: 
      drawPath.lineTo(touchX, touchY); 
      drawCanvas.drawPath(drawPath, drawPaint); 
      drawPath = new Path(); 
      break; 
     default: 
      return false; 
     } 
    } else{ 
     return false; 
    } 
    invalidate(); 
    return true; 
    } 
} 

CustomImageView

public class CustomImageView extends ImageView { 
Matrix 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; 
private boolean zoomEnable= true; 
// Remember some things for zooming 
PointF last = new PointF(); 
PointF start = new PointF(); 
float minScale = 1f; 
float maxScale = 5f; 
float[] m; 

int viewWidth, viewHeight; 
static final int CLICK = 3; 
float saveScale = 1f; 
protected float origWidth, origHeight; 
int oldMeasuredWidth, oldMeasuredHeight; 
ScaleGestureDetector mScaleDetector; 
Context context; 
public CustomImageView(Context context) { 
    super(context); 
    sharedConstructing(context); 
} 
public void setZoomEnable(boolean status){ 
    zoomEnable = status; 
} 
public CustomImageView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    sharedConstructing(context); 
} 

private void sharedConstructing(Context context) { 
    super.setClickable(true); 
    this.context = context; 
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 
    matrix = new Matrix(); 
    m = new float[9]; 
    setImageMatrix(matrix); 
    setScaleType(ScaleType.MATRIX); 

    setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      if(zoomEnable){ 
       mScaleDetector.onTouchEvent(event); 
       PointF curr = new PointF(event.getX(), event.getY()); 

       switch (event.getAction()) { 
       case MotionEvent.ACTION_DOWN: 
        last.set(curr); 
        start.set(last); 
        mode = DRAG; 
        break; 

       case MotionEvent.ACTION_MOVE: 
        if (mode == DRAG) { 
         float deltaX = curr.x - last.x; 
         float deltaY = curr.y - last.y; 
         float fixTransX = getFixDragTrans(deltaX, viewWidth, 
           origWidth * saveScale); 
         float fixTransY = getFixDragTrans(deltaY, viewHeight, 
           origHeight * saveScale); 
         matrix.postTranslate(fixTransX, fixTransY); 
         fixTrans(); 
         last.set(curr.x, curr.y); 
        } 
        break; 

       case MotionEvent.ACTION_UP: 
        mode = NONE; 
        int xDiff = (int) Math.abs(curr.x - start.x); 
        int yDiff = (int) Math.abs(curr.y - start.y); 
        if (xDiff < CLICK && yDiff < CLICK) 
         performClick(); 
        break; 

       case MotionEvent.ACTION_POINTER_UP: 
        mode = NONE; 
        break; 
       } 

       setImageMatrix(matrix); 
       invalidate(); 
       return true; // indicate event was handled 

      } else{ 
       return false; 
      } 
     } 

    }); 
} 

public void setMaxZoom(float x) { 
    maxScale = x; 
} 

private class ScaleListener extends 
ScaleGestureDetector.SimpleOnScaleGestureListener { 
    @Override 
    public boolean onScaleBegin(ScaleGestureDetector detector) { 
     mode = ZOOM; 
     return true; 
    } 

    @Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     float mScaleFactor = detector.getScaleFactor(); 
     float origScale = saveScale; 
     saveScale *= mScaleFactor; 
     if (saveScale > maxScale) { 
      saveScale = maxScale; 
      mScaleFactor = maxScale/origScale; 
     } else if (saveScale < minScale) { 
      saveScale = minScale; 
      mScaleFactor = minScale/origScale; 
     } 

     if (origWidth * saveScale <= viewWidth 
       || origHeight * saveScale <= viewHeight) 
      matrix.postScale(mScaleFactor, mScaleFactor, viewWidth/2, 
        viewHeight/2); 
     else 
      matrix.postScale(mScaleFactor, mScaleFactor, 
        detector.getFocusX(), detector.getFocusY()); 

     fixTrans(); 
     return true; 
    } 
} 

void fixTrans() { 
    matrix.getValues(m); 
    float transX = m[Matrix.MTRANS_X]; 
    float transY = m[Matrix.MTRANS_Y]; 

    float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale); 
    float fixTransY = getFixTrans(transY, viewHeight, origHeight 
      * saveScale); 

    if (fixTransX != 0 || fixTransY != 0) 
     matrix.postTranslate(fixTransX, fixTransY); 
} 

float getFixTrans(float trans, float viewSize, float contentSize) { 
    float minTrans, maxTrans; 

    if (contentSize <= viewSize) { 
     minTrans = 0; 
     maxTrans = viewSize - contentSize; 
    } else { 
     minTrans = viewSize - contentSize; 
     maxTrans = 0; 
    } 

    if (trans < minTrans) 
     return -trans + minTrans; 
    if (trans > maxTrans) 
     return -trans + maxTrans; 
    return 0; 
} 

float getFixDragTrans(float delta, float viewSize, float contentSize) { 
    if (contentSize <= viewSize) { 
     return 0; 
    } 
    return delta; 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    viewWidth = MeasureSpec.getSize(widthMeasureSpec); 
    viewHeight = MeasureSpec.getSize(heightMeasureSpec); 

    // 
    // Rescales image on rotation 
    // 
    if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight 
      || viewWidth == 0 || viewHeight == 0) 
     return; 
    oldMeasuredHeight = viewHeight; 
    oldMeasuredWidth = viewWidth; 

    if (saveScale == 1) { 
     // Fit to screen. 
     float scale; 

     Drawable drawable = getDrawable(); 
     if (drawable == null || drawable.getIntrinsicWidth() == 0 
       || drawable.getIntrinsicHeight() == 0) 
      return; 
     int bmWidth = drawable.getIntrinsicWidth(); 
     int bmHeight = drawable.getIntrinsicHeight(); 

     Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight); 

     float scaleX = (float) viewWidth/(float) bmWidth; 
     float scaleY = (float) viewHeight/(float) bmHeight; 
     scale = Math.min(scaleX, scaleY); 
     matrix.setScale(scale, scale); 

     // Center the image 
     float redundantYSpace = (float) viewHeight 
       - (scale * (float) bmHeight); 
     float redundantXSpace = (float) viewWidth 
       - (scale * (float) bmWidth); 
     redundantYSpace /= (float) 2; 
     redundantXSpace /= (float) 2; 

     matrix.postTranslate(redundantXSpace, redundantYSpace); 

     origWidth = viewWidth - 2 * redundantXSpace; 
     origHeight = viewHeight - 2 * redundantYSpace; 
     setImageMatrix(matrix); 
    } 
    fixTrans(); 
    } 
} 

所有最好的