【问题标题】:Android: Scrollable (bitmap) screenAndroid:可滚动(位图)屏幕
【发布时间】:2012-04-11 01:25:37
【问题描述】:

我目前正在 Android 中实现一个视图,该视图涉及使用大于屏幕大小的位图作为背景,然后在其上绘制可绘制对象。这是为了模拟可以水平和垂直滚动的“地图”。

这是通过使用画布然后在此绘制完整的“地图”位图来完成的,然后将其他图像作为叠加层放在顶部,然后仅在屏幕上绘制此可见位。

覆盖触摸事件以在滚动/翻动时重绘屏幕。

我确信这可能会产生大量开销(通过创建完整图像的画布,同时仅使用(绘制)其中的五分之一)并且可以按照解释的不同方式完成,但我只是想知道人们在这种情况下会做什么,也许还有例子?

如果您需要更多信息,请告诉我,

谢谢,

西蒙

【问题讨论】:

    标签: android scroll bitmap


    【解决方案1】:

    我使用BitmapRegionDecoder API 编写了an example 如何做到这一点。该示例有一个大的 (6000,4000) image of the world,用户可以在全分辨率下滚动。 initial tag 非常小且易于理解。

    【讨论】:

      【解决方案2】:

      我将这个类写到我正在开发的项目中。

      public class ScrollableImage extends View {
          private Bitmap bmLargeImage; // bitmap large enough to be scrolled
          private Rect displayRect = null; // rect we display to
          private Rect scrollRect = null; // rect we scroll over our bitmap with
          private int scrollRectX = 0; // current left location of scroll rect
          private int scrollRectY = 0; // current top location of scroll rect
          private float scrollByX = 0; // x amount to scroll by
          private float scrollByY = 0; // y amount to scroll by
      
          private int width, height;
      
          private Paint background;
      
          public ScrollableImage(Context context, AttributeSet attrs) {
              super(context, attrs);
          }
      
          public ScrollableImage(Context context, AttributeSet attrs, int defStyle) {
              super(context, attrs, defStyle);
          }
      
          public void setSize(int width, int height) {
              background = new Paint();
              background.setColor(Color.WHITE);
              this.width = width;
              this.height = height;
      
              // Destination rect for our main canvas draw. It never changes.
              displayRect = new Rect(0, 0, width, height);
              // Scroll rect: this will be used to 'scroll around' over the
              // bitmap in memory. Initialize as above.
              scrollRect = new Rect(0, 0, width, height);
              // scrollRect = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
          }
      
          public void setImage(Bitmap bmp) {
              if (bmLargeImage != null)
                  bmLargeImage.recycle();
      
          bmLargeImage = bmp;
              scrollRect = new Rect(0, 0, width, height);
              scrollRectX = 0;
              scrollRectY = 0;
              scrollByX = 0;
              scrollByY = 0;
          }
      
          @Override
          public boolean onTouchEvent(MotionEvent event) {
              return true; // done with this event so consume it
          }
      
          public void notifyScroll(float distX, float distY) {
              scrollByX = distX; // move update x increment
              scrollByY = distY; // move update y increment
          }
      
          @Override
          protected void onDraw(Canvas canvas) {
      
              if (bmLargeImage == null)
                  return;
      
              if (scrollByX != 0 || scrollByY != 0) {
                  // Our move updates are calculated in ACTION_MOVE in the opposite     direction
                  // from how we want to move the scroll rect. Think of this as
                  // dragging to
                  // the left being the same as sliding the scroll rect to the right.
                  int newScrollRectX = scrollRectX - (int) scrollByX;
                  int newScrollRectY = scrollRectY - (int) scrollByY;
                  scrollByX = 0;
                  scrollByY = 0;
      
                  // Don't scroll off the left or right edges of the bitmap.
                  if (newScrollRectX < 0)
                      newScrollRectX = 0;
                  else if (newScrollRectX > (bmLargeImage.getWidth() - width))
                      newScrollRectX = (bmLargeImage.getWidth() - width);
      
                  // Don't scroll off the top or bottom edges of the bitmap.
                  if (newScrollRectY < 0)
                      newScrollRectY = 0;
                  else if (newScrollRectY > (bmLargeImage.getHeight() - height))
                      newScrollRectY = (bmLargeImage.getHeight() - height);
                  scrollRect.set(newScrollRectX, newScrollRectY, newScrollRectX
                          + width, newScrollRectY + height);
      
                  scrollRectX = newScrollRectX;
                  scrollRectY = newScrollRectY;
              }
      
              canvas.drawRect(displayRect, background);
              // We have our updated scroll rect coordinates, set them and draw.
              canvas.drawBitmap(bmLargeImage, scrollRect, displayRect, background);
      
          }
      }
      

      在手势监听器中我有这个 onScroll 实现

      img 是您的 ScrollableImage 实例。

      记得在你的大图上使用 setImage。 编辑:也可以使用 setSize 来设置显示的大小。

              public boolean onScroll(MotionEvent e1, MotionEvent e2,
                      float distanceX, float distanceY) {
                      img.notifyScroll(-distanceX, -distanceY);
                      img.invalidate();
                  return true;
              }
      

      【讨论】:

      • 嘿马科斯,太好了,我回家后试试看它是否表现更好。我问 q 的原因是因为我不断收到 OOM 异常。但是我在最后放了一些清理代码(将位图分配给 null 并调用 GC'er,显然我知道那是不确定的,但似乎工作正常)。另外,当我编写代码时,我对 android 还是很陌生,所以可能不是特别聪明。我特别喜欢在我当前的 x,y 坐标上使用 rect 的想法,但感谢您的建议 :)
      【解决方案3】:

      我会将巨大的图像分割成图块,然后根据必须显示图像的哪一部分绘制适当的图块。几乎是谷歌地图所做的。您可以查看http://openzoom.org/。 Android 中没有任何内容,但我认为您可以采用相同的方法。

      【讨论】:

      • 感谢您的建议,我们将仔细阅读该提案,看看它是否比上述更容易实施。
      • 我只是对在内存中保留大位图持怀疑态度。 Android 有很多位图的内存问题,并且正在尝试找到一种巧妙的方法来处理它们。我自己将致力于 Openzoom 类型的实现。 :)
      • 是的,我已经不得不重新考虑一些代码,因为位图问题导致内存出现了一些错误,没有被释放。
      • 嗯,另一种选择是通过 NDK 使用 OpenGL。 Android 中的 Java 对堆内存有 16MB 的限制。据我所知,NDK 没有任何限制,但您必须自己负责释放内存。本帖有详细讨论:stackoverflow.com/questions/3039369/…
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多