Implementing Infinite Scrolling Background With Forefront Image In Android
Solution 1:
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.
publicclassScenarioViewextendsImageView {
Bitmap city1;
Bitmap city2;
Bitmap city3;
Bitmap mCloud1;
Bitmap mCloud2;
Bitmap mCloud3;
privateclassCloudPosition{
int BitmapId;
int mCloudX;
int mCloudY;
}
CloudPosition[] clouds;
privatestaticfinalintMAX_CLOUDS=6;
privateintFRAME_RATE=30;
private Handler mHandler;
privatemSpeed1=5;
privatemSpeed2= mSpeed1 / 2;
publicScenarioView(Context context, AttributeSet attrs){
super(context, attrs);
setBackgroundResource(R.drawable.animation_sky);
mHandler = newHandler();
clouds = newCloudPosition[MAX_CLOUDS];
}
privateRunnabler=newRunnable() {
@Overridepublicvoidrun() {
invalidate();
}
};
publicvoidsetCity1Bitmap(Bitmap city){
city1 = city;
}
publicvoidsetCity2Bitmap(Bitmap city){
city2 = city;
}
publicvoidsetCity3Bitmap(Bitmap city){
city3 = city;
}
privatevoidgenerateCloudPositions() {
introwSeparator= getHeight() / 2;
Randomr=newRandom(System.currentTimeMillis());
intminY=0;
intmaxY= rowSeparator;
intminX=0;
intmaxX= getWidth();
// Generate 1st rowinty= r.nextInt(maxY - minY + 1) + minY;
intx= r.nextInt(maxX - minX + 1) + minX;
intcloudId= 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);
}
publicvoidsetCloudsBitmaps(Bitmap cloud1, Bitmap cloud2, Bitmap cloud3){
mCloud1 = cloud1;
mCloud2 = cloud2;
mCloud3 = cloud3;
generateCloudPositions();
}
privatevoidsetupCloud(int cloudNum, int x, int y, int cloudId){
CloudPositioncp=newCloudPosition();
cp.mCloudX = x;
cp.mCloudY = y;
cp.BitmapId = cloudId;
clouds[cloudNum] = cp;
}
@OverrideprotectedvoidonDraw(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);
}
privatevoiddrawLandscape(Canvas canvas) {
// calculate the wrap factor for matching image drawintnewFarX= city1.getWidth() + mBGFarMoveX;
// if we have scrolled all the way, reset to startintbgY= 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) {
case0:
canvas.drawBitmap(city1, mBGFarMoveX, bgY, null);
canvas.drawBitmap(city2, newFarX, bgY, null);
break;
case1:
canvas.drawBitmap(city2, mBGFarMoveX, bgY, null);
canvas.drawBitmap(city3, newFarX, bgY, null);
break;
case2:
canvas.drawBitmap(city3, mBGFarMoveX, bgY, null);
canvas.drawBitmap(city1, newFarX, bgY, null);
break;
}
}
if(mBGFarMoveX >= 0 && mBGFarMoveX <= getWidth()){
switch (currCity) {
case0:
canvas.drawBitmap(city3, mBGFarMoveX - city3.getWidth(), bgY, null);
canvas.drawBitmap(city1, mBGFarMoveX, bgY, null);
break;
case1:
canvas.drawBitmap(city1, mBGFarMoveX - city1.getWidth(), bgY, null);
canvas.drawBitmap(city2, mBGFarMoveX, bgY, null);
break;
case2:
canvas.drawBitmap(city2, mBGFarMoveX - city2.getWidth(), bgY, null);
canvas.drawBitmap(city3, mBGFarMoveX, bgY, null);
break;
}
}
if(mBGFarMoveX <= 0 && newFarX >= getWidth()){
switch (currCity) {
case0:
canvas.drawBitmap(city1, mBGFarMoveX, bgY, null);
break;
case1:
canvas.drawBitmap(city2, mBGFarMoveX, bgY, null);
break;
case2:
canvas.drawBitmap(city3, mBGFarMoveX, bgY, null);
break;
}
}
}
privatevoiddrawClouds(Canvas canvas) {
intwidth= getWidth();
for(inti=0; i < MAX_CLOUDS; i++){
Bitmap cloud;
clouds[i].mCloudX = clouds[i].mCloudX - mSpeed2;
switch (clouds[i].BitmapId) {
case0:
cloud = mCloud1;
break;
case1:
cloud = mCloud2;
break;
case2:
cloud = mCloud3;
break;
default:
cloud = mCloud1;
break;
}
intcloudX1= clouds[i].mCloudX;
intcloudX2= 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
<FrameLayoutxmlns: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.ScenarioViewandroid:id="@+id/bg_view"android:layout_width="match_parent"android:layout_height="match_parent"android:baselineAlignBottom="true"></com.animation.ScenarioView></FrameLayout>
Solution 2:
Here's a thread which might be of interest to you: How to scroll "infinitely" wide view in Android?
One more thing that I managed to find is this one: http://github.com/commonsguy/cwac-endless Those two can be of big help to you.
One more thing I managed to find is this infinite gallery (seems to me more like a workaround in your case): http://code.google.com/p/infinite-gallery/
And a suggestion regarding the last link:
Have your adapter return some absurdly large number for it's count so the system thinks it's huge and will continue to scroll. Set your initial starting position to the halfway point. You will have a long way to scroll before you actually hit either end. Meanwhile you use a mod operation to keep within your real bounds for accessing your items.
Post a Comment for "Implementing Infinite Scrolling Background With Forefront Image In Android"