2

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

背景图像将由多个水平无限循环的图像组成。并且必须能够前进和后退。

我正在为应该使用哪种方法而苦苦挣扎:

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

我坚持的第二种方法是在 onDraw 中使用自定义视图和动画,在这种情况下哪个更好:ImageView 还是surfaceView?我听说您不应该将其他视图放在动画表面视图前面。

最后一种情况是不得已而为之,是使用特殊的引擎(如andengine)来进行绘图。

就内存管理和易于实施而言,您认为哪种方法最好?

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

如果这种方法奏效,我会发布一个答案样本。

4

2 回答 2

1

我最终使用了 imageView (但我认为可以使用任何视图)。视图使用处理程序根据预定义的 FRAME_RATE 在视图上调用无效。它没有出现在这里,但我使用了对活动的回调来获得基于加速度计的速度。该视图有 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>
于 2013-06-24T12:11:18.240 回答
0

这是您可能感兴趣的主题:如何在 Android 中滚动“无限”宽视图?

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

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

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

让您的适配器返回一些非常大的数字,以便系统认为它很大并且会继续滚动。将您的初始起始位置设置为中点。在实际到达任一端之前,您将有很 的滚动路要走。同时,您使用 mod 操作来保持在您的真实范围内访问您的项目。

于 2013-06-20T13:15:51.613 回答