【问题标题】:How to fix the position of image on a scrollable background?如何在可滚动背景上固定图像的位置?
【发布时间】:2013-07-16 04:57:31
【问题描述】:

如何固定在具有大滚动背景的画布上绘制的图像的位置?

想象一下: 背景图像是房间的图像,对象图像是床、门等。 对象图像绘制在背景之上。

当我滚动背景时,对象应该相对于背景图像移动,对吗? 问题是对象图像也会移动,但位置不会保持不变,即它们从原始位置移动。

这是我的完整类实现。

Bitmap bmImage;
SpriteAnim8 anim;
MThread thread;
PersonAnimated person, person2;
Canvas canvas = new Canvas();

Rect displayRect = null;
Rect scrollRect = null;
int scrollRectX = 0, scrollRectY = 0;
float scrollByX = 0, scrollByY = 0;
float startX = 0, startY = 0;
int initX = 200, initY = 200;

float a = initX, b = initY;

public MGamePanel(Context context) {
    super(context);

    // adding the callback (this) to the surface holder to intercept events
    getHolder().addCallback(this);

    // create Person and load bitmap
    person = new PersonAnimated(BitmapFactory.decodeResource(getResources(), R.drawable.dad_anim),
            10, 200 /* initial position */,
            45, 56 /* width and height of sprite */,
            5, 10); /* FPS and number of frames in the animation */
    // Destination rect for our main canvas draw
    displayRect = new Rect(0, 0, SpriteAnim8.displayWidth, SpriteAnim8.displayHeight);

    // Scroll rect: this will be used to 'scroll around' over the bitmap
    scrollRect = new Rect(0, 0, SpriteAnim8.displayWidth, SpriteAnim8.displayHeight);

    // Load a large bitmap
    bmImage = BitmapFactory.decodeResource(getResources(), R.drawable.l1_plain);

    // create the game loop thread
    thread = new MThread(getHolder(), this);

    // make the GamePanel focusable so it can handle events
    setFocusable(true);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // at this point the surface is created and we can safely start the game
    // loop
    thread.setRunning(true);
    thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.d(TAG, "Surface is being destroyed");
    // tell the thread to shut down and wait for it to finish
    // this is a clean shutdown
    boolean retry = true;
    while (retry) {
        try {
            thread.setRunning(false);
            ((Activity) getContext()).finish();
            retry = false;
        } catch (Exception e) {
            // try again shutting down the thread

        }
    }
    Log.d(TAG, "Thread was shut down cleanly");
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // delegating event handling to the person

         startX = event.getRawX();
         startY = event.getRawY();

        // }
         case MotionEvent.ACTION_MOVE:

        float x = event.getRawX();
        float y = event.getRawY();
        // Calculate move update.
        mScrollByX = x - mStartX + mOldScrollByX; // move update x increment
        mScrollByY = y - mStartY + mOldScrollByX; // move update y increment

        onDraw(canvas);

        break;
    case MotionEvent.ACTION_UP:
        mOldScrollByX = mScrollByX;
        mOldScrollByY = mScrollByY;
        break;
    }
    return true;
}

public void render(Canvas canvas) {

     Paint paint = new Paint();
     canvas.drawBitmap(bmImage, scrollRect, displayRect, paint);
    person.draw(canvas);

}

@Override
protected void onDraw(Canvas canvas) {
    int newScrollRectX = scrollRectX - (int) scrollByX;
    int newScrollRectY = scrollRectY - (int) scrollByY;

    // Prevent scrolling off the left or right edges of the bitmap.
    if (newScrollRectX < 0) {
        newScrollRectX = 0;
    } else if (newScrollRectX > (bmImage.getWidth() - SpriteAnim8.displayWidth)) {
        newScrollRectX = (bmImage.getWidth() - SpriteAnim8.displayWidth);
    }

    // Prevent scrolling off the top or bottom edges of the bitmap.
    if (newScrollRectY < 0) {
        newScrollRectY = 0;
    } else if (newScrollRectY > (bmImage.getHeight() - SpriteAnim8.displayHeight)) {
        newScrollRectY = (bmImage.getHeight() - SpriteAnim8.displayHeight);
    }

    // set the updated scroll rect coordinates.
    scrollRect.set(newScrollRectX, newScrollRectY, newScrollRectX
            + SpriteAnim8.displayWidth, newScrollRectY
            + SpriteAnim8.displayHeight);


    // Reset current scroll coordinates to reflect the latest updates so we
    // can repeat
    scrollRectX = newScrollRectX;
    scrollRectY = newScrollRectY;

    person.setX(person.getX() + scrollByX);
    person.setY(person.getY() + scrollByY);

}

这对吗?

【问题讨论】:

    标签: android image


    【解决方案1】:

    下面是如何滚动画在画布上的图片/图像的代码:

    //define points on the custome view class level
    PointF touchStart = new PointF();
    PointF picStart = new PointF();
    PointF prevPicStart = new PointF();
    

    处理触摸并记住图片的先前位置

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
    
    switch (ev.getAction()) {
    
    case MotionEvent.ACTION_DOWN: {
    
      touchStart.set(ev.getX(), ev.getY());
    
    
      break;
    }
    
    case MotionEvent.ACTION_MOVE: {
    
      float newX = ev.getX() - touchStart.x + prevPicStart.x;
      float newY = ev.getY() - touchStart.y + prevPicStart.y;
    
      //assuming the the picture is bigger than the screen                      
      if ((newX <= 0 && newX > 0 - pic.getWidth() + screenW)){
        picStart.x = newX;                 
      }
    
      if ((newY <= 0 && newY > 0 - pic.getHeight() + screenH)){
        picStart.y = newY;
      }
    
      invalidate();
      break;                            
    }           
    
    case MotionEvent.ACTION_UP:
    
      prevPicStart.x = picStart.x;
      prevPicStart.y = picStart.y;
      break;
    
    }
    return true;
    }
    

    在onDraw中

    canvas.drawBitmap(pic, picStart.x, picStart.y, null);
    

    【讨论】:

    • 可能您需要对 picStart 点添加一些限制,以便图像无法滚动到屏幕或区域之外......但这取决于您想要做什么。
    • @Lumis 当我向右滚动时它工作正常,但是当我向左、向上或向下滚动时,对象会变得混乱并离开屏幕......而且我没有使用 canvas.drawBitmap( ),仍在使用 getX()+picStart.X 我无法弄清楚为什么会这样......你的逻辑看起来很合理,但仍然存在问题
    • 我已经更新了完整的类代码,这样你就可以更好地理解它是如何工作的......
    • 当你在屏幕上滑动手指时,onDraw 每秒会被调用大约 60 次,这意味着像 mDad.setX((mDad.getX() + mScrollByX)); 这样的语句可以让 mDad.x 在一秒钟内变得巨大,因为它正在自我添加。你需要做的是为一个对象创建一个简单的工作代码,当你对它感到满意时,继续添加更多代码,这样如果出现问题,你就会知道它发生在哪里。
    • 我已更新我的帖子以包含图像限制。你为什么不直接用我给你的例子来处理一张图片呢?然后进行下一步。制作连续动画时只需要表面视图和线程。所以你的另一个问题可能是你从两个地方调用 onDraw,而不是一个,应该是线程。
    【解决方案2】:

    不确定您的代码,但您可以使用具有所需背景的 FrameLayout 并添加 ScrollView 作为其子项,该子项将包含其他可滚动的对象。

    HTH!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-11
      • 1970-01-01
      相关资源
      最近更新 更多