2013-02-27 2 views
2

У меня немного замешательство с canvas в андроиде, и мне было интересно, может ли кто-нибудь прояснить некоторые вещи для меня.Android - путаница на холсте (рисование и прокрутка)

настоящее время у меня этот код в моем классе View:

class HomerView extends View { // the custom View for drawing on 
    // set up Bitmap, canvas, path and paint 
    private Bitmap myBitmap; // the initial image we turn into our canvas 
    private Canvas myCanvas; // the canvas we are drawing on 
    private Rect myRect; // the mathematical path of the lines we draw 
    private Paint myBitmapPaint; // the paint we use to draw the bitmap 

    // get the width of the entire tablet screen 
    private int screenWidth = getContext().getResources() 
      .getDisplayMetrics().widthPixels; 
    // get the height of the entire tablet screen 
    private int screenHeight = getContext().getResources() 
      .getDisplayMetrics().heightPixels; 

    private int mX, mY, iX, iY; // current x,y and initial x,y 
    private static final float TOUCH_TOLERANCE = 4; 
    private static final int INVALID_POINTER_ID = -1; 
    private float mPosX; 
    private float mPosY; 
    private BitmapDrawable mImage; 
    private float mLastTouchX; 
    private float mLastTouchY; 
    private int mActivePointerId = INVALID_POINTER_ID; 
    private ScaleGestureDetector mScaleDetector; 
    private float mScaleFactor = 1.f; 

    public HomerView(Context context) { // constructor of HomerView 
     super(context); 
     myBitmap = Bitmap.createBitmap(screenWidth, screenHeight, 
       Bitmap.Config.ARGB_8888); // set our drawable space - the bitmap which becomes the canvas we draw on 
     myCanvas = new Canvas(myBitmap); // set our canvas to our bitmap which we just set up 
     myRect = new Rect(); // make a new rect 
     myBitmapPaint = new Paint(Paint.DITHER_FLAG); // set dither to ON in our saved drawing - gives better color interaction 
     setHorizontalScrollBarEnabled(true); 
     setVerticalScrollBarEnabled(true); 
     TypedArray a = context.obtainStyledAttributes(R.styleable.View); 
     initializeScrollbars(a); 
     a.recycle(); 
     computeVerticalScrollRange(); 
     computeHorizontalScrollRange(); 
     mImage = new BitmapDrawable(getResources(), myBitmap); 
     mScaleDetector = new ScaleGestureDetector(context, 
       new ScaleListener()); 
    } 

    public HomerView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     mScaleDetector = new ScaleGestureDetector(context, 
       new ScaleListener()); 
    } 

    public HomerView(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    protected void onDraw(Canvas canvas) { // method used when we want to draw something to our canvas 
     super.onDraw(canvas); 
     if (addObjectMode == true) { 
      canvas.drawColor(Color.TRANSPARENT); // sets canvas colour 
      canvas.drawBitmap(myBitmap, 0, 0, myBitmapPaint); // save the canvas to bitmap - the numbers are the x, y coords we are drawing from 
      canvas.drawRect(myRect, myPaint); // draw the rectangle that the user has drawn using the paint we set up 
     } else if (moveMode == true) { 
      canvas.save(); 
      System.out.println("X: " + mPosX + " Y: " + mPosY); 
      canvas.translate(mPosX, mPosY); 
      canvas.scale(mScaleFactor, mScaleFactor); 
      mImage.draw(canvas); 
      canvas.restore(); 
     } 

Это своего рода объединение 2-х различных подходов к рисования на экране, как я понимаю. Я понимаю, что у меня есть myBitmap (это то, на что рисуются чертежи пользователей), и это отлично работает для «addObjectMode». Тем не менее, «moveMode» - это когда я хочу, чтобы пользователи могли зажимать прокрутку и т. Д. Вокруг плана дома, который они нарисовали.

В настоящее время я могу нарисовать объекты в порядке, но когда я нажимаю кнопку, чтобы включить moveMode, рисунок исчезает, когда я касаюсь или жест. Я знаю, что это, вероятно, из-за кода в onDraw(); но холсты все еще немного загадочны для меня.

В конце концов, мне понадобится базовая функция отмены/повтора, а также сохранение canvas/bitmap, который будет открыт позже. Может ли кто-нибудь предлагать какие-либо советы или ссылки на любые всеобъемлющие учебники по холсту?

EDIT: это может быть полезно включить мои onTouchEvent методы слишком-

public boolean onTouchEvent(MotionEvent event) { // on any touch event 
     if (addObjectMode == true) { 

      float x = event.getX(); // get current X 
      float y = event.getY(); // get current Y 

      switch (event.getAction()) { // what action is the user performing? 
      case MotionEvent.ACTION_DOWN: // if user is touching down 
       touch_Start(x, y); 
       invalidate(); 
       break; 
      case MotionEvent.ACTION_MOVE: // if user is moving finger while touched down 
       touch_Move(x, y); 
       invalidate(); 
       break; 
      case MotionEvent.ACTION_UP: // if user has released finger 
       touch_Up(); 
       invalidate(); 
       break; 
      } 
      return true; 
     } else if (moveMode == true) { 
      mScaleDetector.onTouchEvent(event); 
      final int action = event.getAction(); 
      switch (action & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: { 
       final float x = event.getX(); 
       final float y = event.getY(); 
       mLastTouchX = x; 
       mLastTouchY = y; 
       mActivePointerId = event.getPointerId(0); 
       break; 
      } 

      case MotionEvent.ACTION_MOVE: { 
       final int pointerIndex = event 
         .findPointerIndex(mActivePointerId); 
       final float x = event.getX(pointerIndex); 
       final float y = event.getY(pointerIndex); 

       // Only move if the ScaleGestureDetector isn't processing a gesture. 
       if (!mScaleDetector.isInProgress()) { 
        final float dx = x - mLastTouchX; 
        final float dy = y - mLastTouchY; 
        mPosX += dx; 
        mPosY += dy; 
        invalidate(); 
       } 
       mLastTouchX = x; 
       mLastTouchY = y; 
       break; 
      } 

      case MotionEvent.ACTION_UP: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_CANCEL: { 
       mActivePointerId = INVALID_POINTER_ID; 
       break; 
      } 

      case MotionEvent.ACTION_POINTER_UP: { 
       final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 
       final int pointerId = event.getPointerId(pointerIndex); 
       if (pointerId == mActivePointerId) { 
        // This was our active pointer going up. Choose a new 
        // active pointer and adjust accordingly. 
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
        mLastTouchX = event.getX(newPointerIndex); 
        mLastTouchY = event.getY(newPointerIndex); 
        mActivePointerId = event.getPointerId(newPointerIndex); 
       } 
       break; 
      } 
      } 
      return true; 
     } else { 
      return false; 
     } 
    } 

ответ

1

В вашем примере, когда вы в moveMode, вы ничего не рисуете на своем последнем холсте.

Даже если вы применяете преобразования к чему-то уже нарисованному, имейте в виду, что холст прозрачен между двумя вызовами onDraw(), поэтому вы снова рисуете его.

Я не знаком с функцией отмены повтора, но вы должны быть в состоянии хранить копию растрового изображения канвы в данной точке, чтобы восстановить его позже

Bitmap.copy()

быть осторожным, что хранящем большое количество растровых изображений может быть довольно тяжелым для мобильной среды, поэтому вам придется ограничить размер стека отмены.

+0

А ... не строка 'mImage.draw (canvas);' рисовать на холст? Вместо этого добавлено '\t \t \t \t canvas.drawBitmap (myBitmap, 0, 0, myBitmapPaint);' before canvas.restore(); Это работает, хотя, когда я затем зажимаю зум и переключаюсь в режим рисования, он сразу возвращается к исходному уровню масштабирования, как если бы прокрутки не было. Любая идея почему? –

+0

Да, так же, как ваш рисунок не применим к вашему movemode, ваши преобразования перевода не применяются к вашему drawMode здесь;) – Guian

+0

Я предлагаю вам выделить механизм перемещения/рисования из метода рисования, нарисовать его на уникальный вывод растрового изображения для пользовательских событий. то по методу onDraw выведите только растровое изображение вывода. – Guian

0

снимите if else if условие на метод вытягивания, и отменить функцию сделать ArrayList из растрового изображения, и сохранить растровое изображение каждый раз, когда пользователь делает какое-то действие, затем отменять замену растрового изображения на предыдущее и аннулировать вид

+0

Я хочу, чтобы у пользователя было 2 "сенсорных режима" - рисование и перемещение. Если еще нужно выполнить соответствующий код прикосновением. Без 'if else if' я могу рисовать, но когда в moveMode ничего не происходит. –

+0

Если вы находитесь в режиме перемещения, почему пропускаете режим рисования?сначала нарисуйте вещь растровое изображение, а масштаб - –

+0

Режим рисования = пользователь рисует прямоугольники, режим движения = пользователь может зажать масштаб и прокрутить вокруг своих прямоугольников. –

0

Для реализации Undo \ Redo вам необходимо поддерживать список путей ... и вам необходимо сохранить эти пути в своем списке путей соответственно. Я прикрепил свой код ниже, посмотрю на него, тогда вы получите четкую идею о функциональности отмены отмены.

 public static LinkedList<Path> rrPathList=new LinkedList<Path>(); 
    public static LinkedList<Path> mPathList=new LinkedList<Path>(); 
    protected void onDraw(Canvas canvas) { 

      for(i = 0; i < mPathList.size() && i < sPaint.size(); i++) 
      { 
       canvas.drawPath(mPathList.get(i),sPaint.get(i)); 

      } 
      } 
    // In your touch up method store the paths into mPathList 
     private void touch_up() {  
      mCanvas.drawPath(mPath, mPaint); 
      mPathList.add(mPath); 
     } 
    // Undo function 
    public void undo() 
    { 
     try 
     { 
      if(mPathList.size()>0) 
      { 
       rPathList.add(mPathList.getLast()); 
       mPathList.removeLast(); 

       invalidate(); 
      } 
     }catch(ArrayIndexOutOfBoundsException arr) 
     { 
      //Print error; 
     } 
    } 
    // Redo function 
    public void redo() 
    { 
     try 
     { 
      if(rPathList.size()>0) 
      { 
       mPathList.add(rPathList.getLast()); 
       rPathList.removeLast(); 
      invalidate(); 
      } 
     }catch(ArrayIndexOutOfBoundsException arr) 
     { 
      //Handle error 
     } 
    } 

Примечание: Пожалуйста, не забудьте называть «invalidate()». Вызов недействительных результатов «Вызовите холст и перерисуйте объекты mPathList» Попробуйте это. Я работаю с этим кодом ... Спасибо !!!

Смежные вопросы