实现无限滚动的背景,在Android的前列图像前列、图像、背景、Android

2023-09-06 00:04:23 作者:繁华落尽、倾城殇

我试着做一做无限滚动的背景与静止图像的前列,同样也视差效果。这种效应会在只使用一次,用户presses一键进入应用程序之前。

背景图像将组成若干图像通过他们的无限循环horizo​​ntaly.And必须能够前进和后退的。

我挣扎,我应该使用哪一种方法:

我想我会找你麻烦,如果我使用horizo​​ntalscollView并保持切换图像。 (例如:当我通过第2图像结束时,把第一个到最后)

第二种类型的方法,我因子评分最高使用自定义视图和OnDraw中动画,在这种情况下,这是更好:和ImageView的或surfaceView?我听说你不应该把其他意见动画surfaceView面前。

最后一种情况是一种不得已而为之的,是用一种特殊的发动机(如andengine)做绘图。

哪一个你认为是在执行的memmory管理和易用性?

而言,最好的方法

更新:我决定使用ImageView的(我认为,任何观点都可以使用)绘制的一切。 Z-指数是用绘制顺序。这样,给我的自由移动不同的背景以不同的速度进行视差效果。我基于该解决方案松散的这场平局功能并采用了postDelayed上的处理程序的视图和强制重绘无效。

如果这个作品形式给出了我会后回答样本。

解决方案

最后我用一个ImageView的(但我认为,任何观点都可以使用)。该视图使用一个处理程序来调用根据一个predefined帧频无效的图。它不会在这里出现,但我用一个回调到活动中获得速度至极是基于加速度计。该视图有3位图作为滚动背景和随机从3位图产生的6云。云滚动以一半的背景速度。

请注意:最好是用函数来获取屏幕宽度,而不是视图的高度和宽度,高度,因为当你设置图像的观点可能没有被夸大,并具有宽度和高度等于0

 公共类ScenarioView扩展ImageView的{
    位图city1;
    位图城2;
    位图city3;

    位图mCloud1;
    位图mCloud2;
    位图mCloud3;

    私有类CloudPosition {
        INT BitmapId;
        INT mCloudX;
        INT mCloudY;
    }

    CloudPosition []云;

    私有静态最终诠释MAX_CLOUDS = 6;

    私人诠释帧频= 30;
    私人处理器mHandler;
    私人mSpeed​​1 = 5;
    私人mSpeed​​2 = mSpeed​​1 / 2;

    公共ScenarioView(上下文的背景下,ATTRS的AttributeSet){
        超(背景下,ATTRS);
        setBackgroundResource(R.drawable.animation_sky);
        mHandler =新的处理程序();
        云=新CloudPosition [MAX_CLOUDS]
    }

    私人Runnable接口R =新的Runnable(){

        @覆盖
        公共无效的run(){
            无效();
        }
    };

    公共无效setCity1Bitmap(位图市){
        city​​1 =城市;
    }

    公共无效setCity2Bitmap(位图市){
        城2 =城市;
    }

    公共无效setCity3Bitmap(位图市){
        city​​3 =城市;
    }

    私人无效generateCloudPositions(){
        INT rowSeparator =的getHeight()/ 2;
        随机R =新的随机(System.currentTimeMillis的());
        INT MINY = 0;
        INT MAXY = rowSeparator;
        INT其minX = 0;
        INT MAXX =的getWidth();

        //生成第一排
        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();
        //生成第二排
        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);
     }

    公共无效setCloudsBitmaps(位图cloud1,位图cloud2,位图cloud3){
        mCloud1 = cloud1;
        mCloud2 = cloud2;
        mCloud3 = cloud3;
        generateCloudPositions();
    }

    私人无效setupCloud(INT cloudNum,诠释的x,INT Y,诠释cloudId){
        CloudPosition CP =新CloudPosition();
        cp.mCloudX = X;
        cp.mCloudY = Y;
        cp.BitmapId = cloudId;
        云[cloudNum] = CP;
    }

    @覆盖
    保护无效的OnDraw(帆布油画){
        super.onDraw(画布);
        mSpeed​​1 = mCallbacks.getSpeed​​();
        mSpeed​​2 = mSpeed​​1 / 2;
        mBGFarMoveX = mBGFarMoveX  -  mSpeed​​1;
        //递减接近背景
        mBGNearMoveX = mBGNearMoveX  -  mSpeed​​1;

        如果(city1 = NULL和放大器;!&安培;城2 = NULL和放大器;!&安培;!city3 = NULL){
            如果(mCloud1 = NULL和放大器;!&安培; mCloud2 = NULL和放大器;!&安培;!mCloud3 = NULL){
                drawClouds(画布);
            }
            drawLandscape(画布);
        }

        如果(MCAR!= NULL){
            canvas.drawBitmap(MCAR,mCarX,mCarY,NULL);
        }

        如果(mWheel!= NULL){
            drawWheels(画布);
        }

        如果(mBridge!= NULL){
            吊桥(画布);
        }

        mHandler.postDelayed(R,帧速率);
    }

    私人无效drawLandscape(帆布油画){
        //计算保鲜因子匹配图像平局
        INT newFarX = city1.getWidth()+ mBGFarMoveX;
        //如果我们已经滚动一路,复位启动
        INT BGY =的getHeight() -  city1.getHeight();

        如果(mSpeed​​1大于0&安培;&安培; newFarX&所述; = 0){
            mBGFarMoveX = 0;
            increseLandscape();
        }

        如果(mSpeed​​1&℃,安培;&安培; mBGFarMoveX> =的getWidth()){
            mBGFarMoveX =(mBGFarMoveX  -  city1.getWidth());
            decreseLandscape();
         }

        如果(newFarX> = 0&安培;&安培; newFarX&其中; =的getWidth()){
            开关(currCity){
            情况下0:
                canvas.drawBitmap(city1,mBGFarMoveX,BGY,NULL);
                canvas.drawBitmap(城2,newFarX,BGY,NULL);
                打破;
            情况1:
                canvas.drawBitmap(城2,mBGFarMoveX,BGY,NULL);
                canvas.drawBitmap(city3,newFarX,BGY,NULL);
                打破;
            案例2:
                canvas.drawBitmap(city3,mBGFarMoveX,BGY,NULL);
                canvas.drawBitmap(city1,newFarX,BGY,NULL);
                打破;
            }
        }
        如果(mBGFarMoveX> = 0&安培;&安培; mBGFarMoveX&其中; =的getWidth()){
            开关(currCity){
            情况下0:
                canvas.drawBitmap(city3,mBGFarMoveX  -  city3.getWidth(),BGY,NULL);
                canvas.drawBitmap(city1,mBGFarMoveX,BGY,NULL);
                打破;
            情况1:
                canvas.drawBitmap(city1,mBGFarMoveX  -  city1.getWidth(),BGY,NULL);
                canvas.drawBitmap(城2,mBGFarMoveX,BGY,NULL);
                打破;
            案例2:
                canvas.drawBitmap(城2,mBGFarMoveX  -  city2.getWidth(),BGY,NULL);
                canvas.drawBitmap(city3,mBGFarMoveX,BGY,NULL);
                打破;
            }
        }
        如果(mBGFarMoveX&所述; = 0&安培;&安培; newFarX> =的getWidth()){
            开关(currCity){
            情况下0:
                canvas.drawBitmap(city1,mBGFarMoveX,BGY,NULL);
                打破;
            情况1:
                canvas.drawBitmap(城2,mBGFarMoveX,BGY,NULL);
                打破;
            案例2:
                canvas.drawBitmap(city3,mBGFarMoveX,BGY,NULL);
                打破;
            }
        }
    }

    私人无效drawClouds(帆布油画){
        INT宽度=的getWidth();
        的for(int i = 0; I< MAX_CLOUDS;我++){
            位图云;
            云[我] .mCloudX =浮云[I] .mCloudX  -  mSpeed​​2;
            开关(浮云[I] .BitmapId){
            情况下0:
                云计算= mCloud1;
                打破;
            情况1:
                云计算= mCloud2;
                打破;
            案例2:
                云计算= mCloud3;
                打破;
            默认:
                云计算= mCloud1;
                打破;
            }
            INT cloudX1 =浮云[I] .mCloudX;
            INT cloudX2 = cloudX1 + cloud.getWidth();

            如果(cloudX2&所述; = 0&安培;&安培; mSpeed​​2大于0){
            云彩[I] .mCloudX =云层[I] .mCloudX +(5 * cloud.getWidth());
            cloudX1 =浮云[I] .mCloudX;
            cloudX2 = cloudX1 + cloud.getWidth();
        }
        如果(cloudX1> =宽度安培;&安培; mSpeed​​2℃,){
                云彩[I] .mCloudX =云层[Ⅰ] .mCloudX  - (5 * cloud.getWidth());
                cloudX1 =浮云[I] .mCloudX;
                cloudX2 = cloudX1 + cloud.getWidth();
            }
            如果(cloudX1&其中;宽度安培;&安培; cloudX2大于0){
                canvas.drawBitmap(云,云[I] .mCloudX,云[I] .mCloudY,NULL);
            }
        }

    }
}
 
ppt如何做随着背景音乐滚动的图片

然后我用这样的观点

 <的FrameLayout
    的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    的xmlns:工具=htt​​p://schemas.android.com/tool​​s
    机器人:ID =@ + ID /容器
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent>

    < com.animation.ScenarioView
        机器人:ID =@ + ID / bg_view
        机器人:layout_width =match_parent
        机器人:layout_height =match_parent
        机器人:baselineAlignBottom =真正的>

    < /com.animation.ScenarioView>

< /的FrameLayout>
 

I'm trying do do a infinite scrolling background with a still image in the forefront, similar too a parallax effect. This effect will be in used only once, before the user presses a button to enter the app.

The background image will be composed of several images looping infinitely through them horizontaly.And has to be able to go forward and backward.

I'm struggling with which kind of approach i should use:

I think i'm going to find trouble if i use an horizontalscollView and keep switching images. (example: when i pass the end of the 2nd image, put the 1st in the end)

The second type of approach i tought up is using a custom view and animate in onDraw, in this case which is better: and ImageView or a surfaceView? I heard you should not put other views in front of an animated surfaceView.

The last case is kind of a last resort, is use a special engine (like andengine) to do the drawing.

Which to you think is the best approach in terms of memmory management and ease of implementation?

UPDATE: I decided on using an ImageView (i think any view can be used) to draw everything. "z-index" is made with the drawing order. This way gave me the freedom to move different backgrounds at different speeds for the parallax effect. I based the solution loosely on this draw function and used a postDelayed on a handler to invalidate the view and force redrawing.

If this aproach works out i'll post an answer sample.

解决方案

I ended up using an imageView (but i think any view can be used). The view uses a handler to call invalidate on the view according to a predefined FRAME_RATE. it doesn't appear here but i used a callback to the activity to get the speed wich was based on the accelerometer. The view has 3 bitmaps as the scrolling background and 6 clouds that are randomly generated from 3 bitmaps. The clouds scroll at half the background speed.

NOTE: it's better to use functions to get the screen width and height instead of the view's height and width because when you are setting up the images the view might not have been inflated and has width and height equal to 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);
            }
        }

    }
}

Then i used the view like this

<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>