package com.dahuo.learn.header; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.view.View; import android.view.animation.Animation; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; import com.dahuo.learn.startup.R; import in.srain.cube.views.ptr.util.PtrLocalDisplay; public class RentalsSunDrawable extends Drawable implements Animatable { private static final float SCALE_START_PERCENT = 0.3f; private static final int ANIMATION_DURATION = 1000; private final static float SKY_RATIO = 0.65f; private static final float SKY_INITIAL_SCALE = 1.05f; private final static float TOWN_RATIO = 0.22f; private static final float TOWN_INITIAL_SCALE = 1.20f; private static final float TOWN_FINAL_SCALE = 1.30f; private static final float SUN_FINAL_SCALE = 0.75f; private static final float SUN_INITIAL_ROTATE_GROWTH = 1.2f; private static final float SUN_FINAL_ROTATE_GROWTH = 1.5f; private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); private View mParent; private Matrix mMatrix; private Animation mAnimation; private int mTop; private int mScreenWidth; private int mSkyHeight; private float mSkyTopOffset; private float mSkyMoveOffset; private int mTownHeight; private float mTownInitialTopOffset; private float mTownFinalTopOffset; private float mTownMoveOffset; private int mSunSize = 100; private float mSunLeftOffset; private float mSunTopOffset; private float mPercent = 0.0f; private float mRotate = 0.0f; private Bitmap mSky; private Bitmap mSun; private Bitmap mTown; private boolean isRefreshing = false; private Context mContext; private int mTotalDragDistance; public RentalsSunDrawable(Context context, View parent) { mContext = context; mParent = parent; mMatrix = new Matrix(); initiateDimens(); createBitmaps(); setupAnimations(); } private Context getContext() { return mContext; } private void initiateDimens() { PtrLocalDisplay.init(mContext); mTotalDragDistance = PtrLocalDisplay.dp2px(120); mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels; mSkyHeight = (int) (SKY_RATIO * mScreenWidth); mSkyTopOffset = -(mSkyHeight * 0.28f); mSkyMoveOffset = PtrLocalDisplay.designedDP2px(15); mTownHeight = (int) (TOWN_RATIO * mScreenWidth); mTownInitialTopOffset = (mTotalDragDistance - mTownHeight * TOWN_INITIAL_SCALE) + mTotalDragDistance * .42f; mTownFinalTopOffset = (mTotalDragDistance - mTownHeight * TOWN_FINAL_SCALE) + mTotalDragDistance * .42f; mTownMoveOffset = PtrLocalDisplay.designedDP2px(10); mSunLeftOffset = 0.3f * (float) mScreenWidth; mSunTopOffset = (mTotalDragDistance * 0.5f); mTop = 0; } private void createBitmaps() { mSky = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sky); mSky = Bitmap.createScaledBitmap(mSky, mScreenWidth, mSkyHeight, true); mTown = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.buildings); mTown = Bitmap.createScaledBitmap(mTown, mScreenWidth, (int) (mScreenWidth * TOWN_RATIO), true); mSun = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sun); mSun = Bitmap.createScaledBitmap(mSun, mSunSize, mSunSize, true); } public void offsetTopAndBottom(int offset) { mTop = offset; invalidateSelf(); } @Override public void draw(Canvas canvas) { final int saveCount = canvas.save(); canvas.translate(0, mTotalDragDistance - mTop); drawSky(canvas); drawSun(canvas); drawTown(canvas); canvas.restoreToCount(saveCount); } private void drawSky(Canvas canvas) { Matrix matrix = mMatrix; matrix.reset(); int y = Math.max(0, mTop - mTotalDragDistance); // 0 ~ 1 float dragPercent = Math.min(1f, Math.abs(mPercent)); /** Change skyScale between {@link #SKY_INITIAL_SCALE} and 1.0f depending on {@link #mPercent} */ float skyScale; float scalePercentDelta = dragPercent - SCALE_START_PERCENT; /** less than {@link SCALE_START_PERCENT} will be {@link SKY_INITIAL_SCALE} */ if (scalePercentDelta > 0) { /** will change from 0 ~ 1 **/ float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT); skyScale = SKY_INITIAL_SCALE - (SKY_INITIAL_SCALE - 1.0f) * scalePercent; } else { skyScale = SKY_INITIAL_SCALE; } float offsetX = -(mScreenWidth * skyScale - mScreenWidth) / 2.0f; float offsetY = y + 50 + mSkyTopOffset // Offset canvas moving, goes lower when goes down - mSkyHeight * (skyScale - 1.0f) / 2 // Offset sky scaling, lower than 0, will go greater when goes down + mSkyMoveOffset * dragPercent; // Give it a little move top -> bottom // will go greater when goes down matrix.postScale(skyScale, skyScale); matrix.postTranslate(offsetX, offsetY); canvas.drawBitmap(mSky, matrix, null); } private void drawTown(Canvas canvas) { Matrix matrix = mMatrix; matrix.reset(); int y = Math.max(0, mTop - mTotalDragDistance); float dragPercent = Math.min(1f, Math.abs(mPercent)); float townScale; float townTopOffset; float townMoveOffset; float scalePercentDelta = dragPercent - SCALE_START_PERCENT; if (scalePercentDelta > 0) { /** * Change townScale between {@link #TOWN_INITIAL_SCALE} and {@link #TOWN_FINAL_SCALE} depending on {@link #mPercent} * Change townTopOffset between {@link #mTownInitialTopOffset} and {@link #mTownFinalTopOffset} depending on {@link #mPercent} */ float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT); townScale = TOWN_INITIAL_SCALE + (TOWN_FINAL_SCALE - TOWN_INITIAL_SCALE) * scalePercent; townTopOffset = mTownInitialTopOffset - (mTownFinalTopOffset - mTownInitialTopOffset) * scalePercent; townMoveOffset = mTownMoveOffset * (1.0f - scalePercent); } else { float scalePercent = dragPercent / SCALE_START_PERCENT; townScale = TOWN_INITIAL_SCALE; townTopOffset = mTownInitialTopOffset; townMoveOffset = mTownMoveOffset * scalePercent; } float offsetX = -(mScreenWidth * townScale - mScreenWidth) / 2.0f; // float offsetY = (1.0f - dragPercent) * mTotalDragDistance // Offset canvas moving float offsetY = y + +townTopOffset - mTownHeight * (townScale - 1.0f) / 2 // Offset town scaling + townMoveOffset; // Give it a little move matrix.postScale(townScale, townScale); matrix.postTranslate(offsetX, offsetY); canvas.drawBitmap(mTown, matrix, null); } private void drawSun(Canvas canvas) { Matrix matrix = mMatrix; matrix.reset(); float dragPercent = mPercent; if (dragPercent > 1.0f) { // Slow down if pulling over set height dragPercent = (dragPercent + 9.0f) / 10; } float sunRadius = (float) mSunSize / 2.0f; float sunRotateGrowth = SUN_INITIAL_ROTATE_GROWTH; float offsetX = mSunLeftOffset; float offsetY = mSunTopOffset + (mTotalDragDistance / 2) * (1.0f - dragPercent); // Move the sun up float scalePercentDelta = dragPercent - SCALE_START_PERCENT; if (scalePercentDelta > 0) { float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT); float sunScale = 1.0f - (1.0f - SUN_FINAL_SCALE) * scalePercent; sunRotateGrowth += (SUN_FINAL_ROTATE_GROWTH - SUN_INITIAL_ROTATE_GROWTH) * scalePercent; matrix.preTranslate(offsetX + (sunRadius - sunRadius * sunScale), offsetY * (2.0f - sunScale)); matrix.preScale(sunScale, sunScale); offsetX += sunRadius; offsetY = offsetY * (2.0f - sunScale) + sunRadius * sunScale; } else { matrix.postTranslate(offsetX, offsetY); offsetX += sunRadius; offsetY += sunRadius; } float r = (isRefreshing ? -360 : 360) * mRotate * (isRefreshing ? 1 : sunRotateGrowth); matrix.postRotate(r, offsetX, offsetY); canvas.drawBitmap(mSun, matrix, null); } public void setPercent(float percent) { mPercent = percent; setRotate(percent); } public void setRotate(float rotate) { mRotate = rotate; mParent.invalidate(); invalidateSelf(); } public void resetOriginals() { setPercent(0); setRotate(0); } @Override public void setBounds(int left, int top, int right, int bottom) { super.setBounds(left, top, right, mSkyHeight + top); } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } @Override public boolean isRunning() { return false; } @Override public void start() { mAnimation.reset(); isRefreshing = true; mParent.startAnimation(mAnimation); } @Override public void stop() { mParent.clearAnimation(); isRefreshing = false; resetOriginals(); } private void setupAnimations() { mAnimation = new Animation() { @Override public void applyTransformation(float interpolatedTime, Transformation t) { setRotate(interpolatedTime); } }; mAnimation.setRepeatCount(Animation.INFINITE); mAnimation.setRepeatMode(Animation.RESTART); mAnimation.setInterpolator(LINEAR_INTERPOLATOR); mAnimation.setDuration(ANIMATION_DURATION); } public int getTotalDragDistance() { return mTotalDragDistance; } }