在android中使用前端图像实现无限滚动背景

时间:2013-06-20 11:31:48

标签: android animation background parallax

我正在尝试使用最前面的静止图像进行无限滚动背景,类似于视差效果。在用户按下按钮进入应用程序之前,此效果将仅使用一次。

背景图像将由几个无限延伸通过它们的图像组成。并且必须能够前进和后退。

我正在努力应该使用哪种方法:

如果我使用horizo​​ntalscollView并继续切换图像,我想我会遇到麻烦。 (例如:当我通过第二张图像的结尾时,将第一张图片放在最后)

我想要的第二种方法是在onDraw中使用自定义视图和动画,在这种情况下更好:和ImageView或SurfaceView?我听说你不应该在动画surfaceView前面放置其他视图。

最后一种情况是最后的手段,是使用特殊引擎(如andengine)进行绘图。

您认为哪个是内存管理和易于实施的最佳方法?

更新:我决定使用ImageView(我认为可以使用任何视图)来绘制所有内容。 “z-index”是使用绘图顺序制作的。这种方式让我可以自由地以不同的速度移动不同的背景来实现视差效果。我在this draw function上松散地使用解决方案,并在处理程序上使用postDelayed使视图无效并强制重绘。

如果这个方法成功,我会发一个答案样本。

2 个答案:

答案 0 :(得分:0)

以下是您可能感兴趣的主题:How to scroll "infinitely" wide view in Android?

我设法找到的另一件事就是这一件事:http://github.com/commonsguy/cwac-endless 这两个对你有很大的帮助。

我设法找到的另一件事是这个无限的画廊(在我看来,更像是一个解决方案): http://code.google.com/p/infinite-gallery/

关于最后一个链接的建议:

  

让你的适配器返回一些荒谬的大数字,因为它的数量   系统认为它很大并且会继续滚动。设置你的   初始起始位置到中途点。你将有一个   在实际击中任意一端之前滚动的方法。同时你用一个   mod操作,以保持您的真实边界访问您的   项目

答案 1 :(得分:0)

我最终使用了一个imageView(但我认为可以使用任何视图)。视图使用处理程序根据预定义的FRAME_RATE在视图上调用invalidate。它没有出现在这里,但我使用回调活动来获得基于加速度计的速度。视图有3个位图作为滚动背景,6个云是从3个位图随机生成的。云以一半的背景速度滚动。

注意:最好使用函数来获取屏幕宽度和高度,而不是视图的高度和宽度,因为在设置图像时,视图可能没有被充气,宽度和高度等于0。

public class ScenarioView extends ImageView {
    Bitmap city1;
    Bitmap city2;
    Bitmap city3;

    Bitmap mCloud1;
    Bitmap mCloud2;
    Bitmap mCloud3;

    private class CloudPosition{
        int BitmapId;
        int mCloudX;
        int mCloudY;
    }

    CloudPosition[] clouds;

    private static final int MAX_CLOUDS = 6;

    private int FRAME_RATE = 30;
    private Handler mHandler;
    private mSpeed1 = 5;
    private mSpeed2 = mSpeed1 / 2;

    public ScenarioView(Context context, AttributeSet attrs){
        super(context, attrs);
        setBackgroundResource(R.drawable.animation_sky);
        mHandler = new Handler();   
        clouds = new CloudPosition[MAX_CLOUDS];
    }

    private Runnable r = new Runnable() {

        @Override
        public void run() {
            invalidate();           
        }
    };

    public void setCity1Bitmap(Bitmap city){
        city1 = city;
    }

    public void setCity2Bitmap(Bitmap city){
        city2 = city;
    }

    public void setCity3Bitmap(Bitmap city){
        city3 = city;
    }

    private void generateCloudPositions() {
        int rowSeparator = getHeight() / 2;
        Random r = new Random(System.currentTimeMillis());
        int minY = 0;
        int maxY = rowSeparator;
        int minX = 0;
        int maxX = getWidth();

        // Generate 1st row
        int y = r.nextInt(maxY - minY + 1) + minY;
        int x = r.nextInt(maxX - minX + 1) + minX;
        int cloudId = r.nextInt(3);
        setupCloud(0, x, y, cloudId);

        y = r.nextInt(maxY - minY + 1) + minY;
        x = r.nextInt(maxX - minX + 1) + minX;
        cloudId = r.nextInt(3);
        setupCloud(1, x, y, cloudId);

        y = r.nextInt(maxY - minY + 1) + minY;
        x = r.nextInt(maxX - minX + 1) + minX;
        cloudId = r.nextInt(3);
        setupCloud(2, x, y, cloudId);

        minY = rowSeparator;
        maxY = getHeight();
        // Generate 2nd row
        y = r.nextInt(maxY - minY + 1) + minY;
        x = r.nextInt(maxX - minX + 1) + minX;
        cloudId = r.nextInt(3);
        setupCloud(3, x, y, cloudId);

        y = r.nextInt(maxY - minY + 1) + minY;
        x = r.nextInt(maxX - minX + 1) + minX;
        cloudId = r.nextInt(3);
        setupCloud(4, x, y, cloudId);

        y = r.nextInt(maxY - minY + 1) + minY;
        x = r.nextInt(maxX - minX + 1) + minX;
        cloudId = r.nextInt(3);
        setupCloud(5, x, y, cloudId);
     }

    public void setCloudsBitmaps(Bitmap cloud1, Bitmap cloud2, Bitmap cloud3){
        mCloud1 = cloud1;
        mCloud2 = cloud2;
        mCloud3 = cloud3;
        generateCloudPositions();
    }

    private void setupCloud(int cloudNum, int x, int y, int cloudId){
        CloudPosition cp = new CloudPosition();
        cp.mCloudX = x;
        cp.mCloudY = y;
        cp.BitmapId = cloudId;
        clouds[cloudNum] = cp;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mSpeed1 = mCallbacks.getSpeed();
        mSpeed2 = mSpeed1 / 2;
        mBGFarMoveX = mBGFarMoveX - mSpeed1;
        // decrement the near background
        mBGNearMoveX = mBGNearMoveX - mSpeed1;

        if(city1 != null && city2 != null && city3 != null){
            if(mCloud1 != null && mCloud2 != null && mCloud3 != null){
                drawClouds(canvas);
            }
            drawLandscape(canvas);
        }

        if(mCar != null){
            canvas.drawBitmap(mCar, mCarX, mCarY, null);
        }

        if(mWheel != null){
            drawWheels(canvas);
        }

        if(mBridge != null){
            drawBridge(canvas);
        }

        mHandler.postDelayed(r, FRAME_RATE);
    }

    private void drawLandscape(Canvas canvas) {
        // calculate the wrap factor for matching image draw
        int newFarX = city1.getWidth() + mBGFarMoveX;
        // if we have scrolled all the way, reset to start
        int bgY = getHeight() - city1.getHeight();

        if(mSpeed1 > 0 && newFarX <= 0){
            mBGFarMoveX = 0;    
            increseLandscape();
        }

        if(mSpeed1 < 0 && mBGFarMoveX >= getWidth()){
            mBGFarMoveX = (mBGFarMoveX - city1.getWidth());
            decreseLandscape();
         }

        if(newFarX >= 0 && newFarX <= getWidth()){  
            switch (currCity) {
            case 0:
                canvas.drawBitmap(city1, mBGFarMoveX, bgY, null);
                canvas.drawBitmap(city2, newFarX, bgY, null);   
                break;
            case 1:
                canvas.drawBitmap(city2, mBGFarMoveX, bgY, null);
                canvas.drawBitmap(city3, newFarX, bgY, null);   
                break;
            case 2:
                canvas.drawBitmap(city3, mBGFarMoveX, bgY, null);
                canvas.drawBitmap(city1, newFarX, bgY, null);   
                break;
            }
        }
        if(mBGFarMoveX >= 0 && mBGFarMoveX <= getWidth()){  
            switch (currCity) {
            case 0:
                canvas.drawBitmap(city3, mBGFarMoveX - city3.getWidth(), bgY, null);    
                canvas.drawBitmap(city1, mBGFarMoveX, bgY, null);                   
                break;
            case 1:
                canvas.drawBitmap(city1, mBGFarMoveX - city1.getWidth(), bgY, null);    
                canvas.drawBitmap(city2, mBGFarMoveX, bgY, null);   
                break;
            case 2:
                canvas.drawBitmap(city2, mBGFarMoveX - city2.getWidth(), bgY, null);
                canvas.drawBitmap(city3, mBGFarMoveX, bgY, null);   
                break;
            }
        }
        if(mBGFarMoveX <= 0 && newFarX >= getWidth()){
            switch (currCity) {
            case 0:
                canvas.drawBitmap(city1, mBGFarMoveX, bgY, null);
                break;
            case 1:
                canvas.drawBitmap(city2, mBGFarMoveX, bgY, null);
                break;
            case 2:
                canvas.drawBitmap(city3, mBGFarMoveX, bgY, null);
                break;
            }
        }
    }

    private void drawClouds(Canvas canvas) {
        int width = getWidth();
        for(int i = 0; i < MAX_CLOUDS; i++){
            Bitmap cloud;
            clouds[i].mCloudX = clouds[i].mCloudX - mSpeed2;
            switch (clouds[i].BitmapId) {
            case 0:
                cloud = mCloud1;
                break;
            case 1:
                cloud = mCloud2;
                break;
            case 2:
                cloud = mCloud3;
                break;
            default:
                cloud = mCloud1;
                break;
            }
            int cloudX1 = clouds[i].mCloudX;
            int cloudX2 = cloudX1 + cloud.getWidth();

            if (cloudX2 <= 0 && mSpeed2 > 0) {
            clouds[i].mCloudX = clouds[i].mCloudX + (5 * cloud.getWidth());
            cloudX1 = clouds[i].mCloudX;
            cloudX2 = cloudX1 + cloud.getWidth();
        }
        if (cloudX1 >= width && mSpeed2 < 0) {
                clouds[i].mCloudX = clouds[i].mCloudX - (5 * cloud.getWidth());
                cloudX1 = clouds[i].mCloudX;
                cloudX2 = cloudX1 + cloud.getWidth();
            }
            if(cloudX1 < width && cloudX2 > 0){
                canvas.drawBitmap(cloud, clouds[i].mCloudX, clouds[i].mCloudY, null);
            }
        }

    }
}

然后我使用了这样的视图

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.animation.ScenarioView 
        android:id="@+id/bg_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:baselineAlignBottom="true">

    </com.animation.ScenarioView>   

</FrameLayout>