package edu.mit.mitmobile2.tour; import edu.mit.mitmobile2.R; import android.content.Context; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.view.View; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; import android.view.animation.Animation.AnimationListener; public class MainTourBackgroundView extends View implements AnimationListener { private static float FADE_IN_FRACTION = 0.20f; private Context mContext; private int[] mBackgroundResourceIds = new int[] { R.drawable.tour_wallpaper_killian, R.drawable.tour_wallpaper_stata, R.drawable.tour_wallpaper_great_sail}; private int mCurrentDrawable = 0; private float mInterpolatedTime = 0; private boolean mDrawablesLoaded = false; private BitmapDrawable mOutgoingDrawable; private BitmapDrawable mIncomingDrawable; private float mOutgoingScale; // scale factor, to get the full height of the image to fit private float mIncomingScale; private float mOutgoingDeltaX; // the total pixel distance the image needs to translate by in one segment of the animation private float mIncomingDeltaX; private BackgroundAnimation mBackgroundAnimation; public MainTourBackgroundView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; mBackgroundAnimation = new BackgroundAnimation(); mBackgroundAnimation.setDuration(8000); mBackgroundAnimation.setRepeatCount(-1); mBackgroundAnimation.setRepeatMode(Animation.RESTART); mBackgroundAnimation.setInterpolator(new LinearInterpolator()); mBackgroundAnimation.setAnimationListener(this); } private void loadDrawables() { if(mIncomingDrawable != null) { mOutgoingDrawable = mIncomingDrawable; } else { mOutgoingDrawable = (BitmapDrawable) mContext.getResources().getDrawable(mBackgroundResourceIds[mCurrentDrawable]); } mIncomingDrawable = (BitmapDrawable) mContext.getResources().getDrawable(mBackgroundResourceIds[(mCurrentDrawable +1) % mBackgroundResourceIds.length]); // calculate scaling and translations // if image is too small we rescale it, otherwise we just crop it int outgoingHeight = mOutgoingDrawable.getIntrinsicHeight(); int outgoingWidth = mOutgoingDrawable.getIntrinsicWidth(); if(outgoingHeight < getHeight()) { mOutgoingScale = ((float) getHeight()) / ((float) outgoingHeight); } else { mOutgoingScale = 1.0f; } mOutgoingDeltaX = (outgoingWidth * mOutgoingScale) - getWidth(); int incomingHeight = mIncomingDrawable.getIntrinsicHeight(); int incomingWidth = mIncomingDrawable.getIntrinsicWidth(); if(incomingHeight < getHeight()) { mIncomingScale = ((float) getHeight()) / ((float) incomingHeight); } else { mIncomingScale = 1.0f; } mIncomingDeltaX = (incomingWidth * mIncomingScale) - getWidth(); mDrawablesLoaded = true; } public void setInterpolation(float interpolatedTime) { mInterpolatedTime = interpolatedTime; } @Override public void onAnimationRepeat(Animation animation) { mCurrentDrawable = (mCurrentDrawable + 1) % mBackgroundResourceIds.length; setInterpolation(0); mDrawablesLoaded = false; } @Override public void onAnimationStart(Animation animation) { } // TODO Auto-generated method stub @Override public void onAnimationEnd(Animation animation) { } // TODO Auto-generated method stub @Override protected void onDraw(Canvas canvas) { if(!mDrawablesLoaded) { loadDrawables(); } // images should start at position x=-deltaX and end at position x=0 // the images are on the screen for one full cycle plus the fade out time // of the next cycle, so a cycle is effectivly 1 + FADE_IN_FRACTION if(mInterpolatedTime < FADE_IN_FRACTION) { Matrix outgoingMatrix = new Matrix(); outgoingMatrix.postScale(mOutgoingScale, mOutgoingScale); float outgoingTransX = -mOutgoingDeltaX + mOutgoingDeltaX * (1 + mInterpolatedTime) / (1 + FADE_IN_FRACTION); outgoingMatrix.postTranslate(Math.round(outgoingTransX), 0.0f); canvas.drawBitmap(mOutgoingDrawable.getBitmap(), outgoingMatrix, null); Matrix incomingMatrix = new Matrix(); incomingMatrix.postScale(mIncomingScale, mIncomingScale); float incomingTransX = -mIncomingDeltaX + mIncomingDeltaX * (mInterpolatedTime) / (1 + FADE_IN_FRACTION); incomingMatrix.postTranslate(Math.round(incomingTransX), 0.0f); Paint translucentPaint = new Paint(); translucentPaint.setAlpha(Math.round(255 * mInterpolatedTime / FADE_IN_FRACTION)); canvas.drawBitmap(mIncomingDrawable.getBitmap(), incomingMatrix, translucentPaint); } else { Matrix incomingMatrix = new Matrix(); incomingMatrix.postScale(mIncomingScale, mIncomingScale); float incomingTransX = -mIncomingDeltaX + mIncomingDeltaX * (mInterpolatedTime) / (1 + FADE_IN_FRACTION); incomingMatrix.postTranslate(Math.round(incomingTransX), 0.0f); canvas.drawBitmap(mIncomingDrawable.getBitmap(), incomingMatrix, null); } } private class BackgroundAnimation extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { setInterpolation(interpolatedTime); invalidate(); } } public void startBackgroundAnimation() { startAnimation(mBackgroundAnimation); } }