How to scroll “infinitely” wide view in Android?

2019-02-07 15:43发布

问题:

I am pondering the alternatives on how to scroll an "infinite", scale-like, control in android. The simple idea is to redraw the entire view on each scroll movement, but somehow it doesn't seem like the proper way. It is possible to draw the contents before-hand, but I have no clue how wide I should make the view in the first place, and what happens when the user scrolls to the end of the view? I guess I need to extend the view towards that direction.

Should I go towards programatically adding (and removing) chunks of view to a linear layout? It would be great to hear what experiences are out there regarding drawing this kind of long-scrolling custom control.

Thanks /Erik

回答1:

if you are working with list/grid or anything that uses Adapter for data, you can use a most excellent class written by CommonsWare and available here:

http://github.com/commonsguy/cwac-endless

it was was specifically for this purpose



回答2:

use an offscreen buffer the size of your control.

at first do it the simple way. Draw the entire offscreenbuffer scrolled to the correct position. When ready blit it to the actual screen.

If this is too slow, try to optimize it by not redrawing the entire offscreenbuffer but by making a vertical split: (I'm only talking about a horizontal scroll movement here for now to make the concept easier to grasp. But this method applies to 8 way scrolling as well)

this is somewhat tricky to implement (that's why I suggested the simple approach first), but try to imagine a paper with picture on it, and the left side you wrap around and glue it to the right side (so you get a tube). This way you can scroll the paper indefinitely (by rotating the tube around it's y axis).

similarly you can do the same with the offscreen buffer.Prepare the offscreen buffer by drawing the complete contents on it.

now to scroll to the right you basically split the offscreen buffer in 2 (by way of this vertical split (just like the paper in the example where the glue was)). suppose you scroll 10 pixels to the right, what you do is:

  • copy the right hand side of the split (located at pixel 10) to pixel 0 of your control. (so the whole region from (10, 0) - (width - height) to: (0,0)
  • then copy the left hand side of the split: pixel 0 to 10 to pixel width-10. so: (0,0)-(10,height) to (width-10, 0)

before you do this ONLY redraw the pixels which have been to be altered (in this case 10 pixels since we scrolled 10 pixels). All other pixels are still identical and don't need redrawing.

You'll have to draw this out on a paper yourself to really understand it. It is a quite common technique with game development on platforms where resources are limited (mobile phones etc).

p.s. scrolling in all directions can be achieved in the exact same way (although it's even harder to get right) ;^)



回答3:

a bit late to the party, but I figured I'd show you a much simpler way to go: you just need the screensize or size of the view your background is in, and then call the following code (assuming you're extending a view and overriding onDraw):

 private void drawEndlessBackground(Canvas canvas, float left, float top) {

    float modLeft = left % screenWidth;

    canvas.drawBitmap(backgroundImage, modLeft, top, null);

    if (left < 0) {

        canvas.drawBitmap(backgroundImage, modLeft + screenWidth, top, null);

    } else {

        canvas.drawBitmap(backgroundImage, modLeft - screenWidth, top, null);

    }



}


回答4:

how about in XML? private void drawEndlessBackground(Canvas canvas, float left, float top) {

float modLeft = left % screenWidth;

canvas.drawBitmap(backgroundImage, modLeft, top, null);

if (left < 0) {

    canvas.drawBitmap(backgroundImage, modLeft + screenWidth, top, null);

} else {

    canvas.drawBitmap(backgroundImage, modLeft - screenWidth, top, null);

}