package in.srain.cube.views.ptr.header; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.PointF; import android.util.AttributeSet; import android.view.View; import android.view.animation.Transformation; import in.srain.cube.views.ptr.PtrFrameLayout; import in.srain.cube.views.ptr.PtrUIHandler; import in.srain.cube.views.ptr.util.PtrLocalDisplay; import java.util.ArrayList; /** * Created by srain on 11/6/14. */ public class StoreHouseHeader extends View implements PtrUIHandler { public ArrayList<StoreHouseBarItem> mItemList = new ArrayList<StoreHouseBarItem>(); private int mLineWidth = PtrLocalDisplay.dp2px(1); private float mScale = 1; private int mDropHeight = PtrLocalDisplay.dp2px(40); private float internalAnimationFactor = 0.7f; private int horizontalRandomness = PtrLocalDisplay.SCREEN_WIDTH_PIXELS / 2; private float mProgress = 0; private int mDrawZoneWidth = 0; private int mDrawZoneHeight = 0; private int mOffsetX = 0; private int mOffsetY = 0; private float mBarDarkAlpha = 0.4f; private float mFromAlpha = 1.0f; private float mToAlpha = 0.4f; private int mLoadingAniDuration = 1000; private int mLoadingAniSegDuration = 1000; private int mLoadingAniItemDuration = 400; private Transformation mTransformation = new Transformation(); private boolean mIsInLoading = false; private AniController mAniController = new AniController(); private int mTextColor = Color.WHITE; public StoreHouseHeader(Context context) { super(context); initView(); } public StoreHouseHeader(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public StoreHouseHeader(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private void initView() { } private void setProgress(float progress) { mProgress = progress; } public int getLoadingAniDuration() { return mLoadingAniDuration; } public void setLoadingAniDuration(int duration) { mLoadingAniDuration = duration; mLoadingAniSegDuration = duration; } public StoreHouseHeader setLineWidth(int width) { mLineWidth = width; for (int i = 0; i < mItemList.size(); i++) { mItemList.get(i).setLineWidth(width); } return this; } public StoreHouseHeader setTextColor(int color) { mTextColor = color; for (int i = 0; i < mItemList.size(); i++) { mItemList.get(i).setColor(color); } return this; } public StoreHouseHeader setDropHeight(int height) { mDropHeight = height; return this; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = getTopOffset() + mDrawZoneHeight + getBottomOffset(); heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); mOffsetX = (getMeasuredWidth() - mDrawZoneWidth) / 2; mOffsetY = getTopOffset(); mDropHeight = getTopOffset(); } private int getTopOffset() { return getPaddingTop() + PtrLocalDisplay.dp2px(10); } private int getBottomOffset() { return getPaddingBottom() + PtrLocalDisplay.dp2px(10); } public void initWithString(String str) { initWithString(str, 25); } public void initWithString(String str, int fontSize) { ArrayList<float[]> pointList = StoreHousePath.getPath(str, fontSize * 0.01f, 14); initWithPointList(pointList); } public void initWithStringArray(int id) { String[] points = getResources().getStringArray(id); ArrayList<float[]> pointList = new ArrayList<float[]>(); for (int i = 0; i < points.length; i++) { String[] x = points[i].split(","); float[] f = new float[4]; for (int j = 0; j < 4; j++) { f[j] = Float.parseFloat(x[j]); } pointList.add(f); } initWithPointList(pointList); } public float getScale() { return mScale; } public void setScale(float scale) { mScale = scale; } public void initWithPointList(ArrayList<float[]> pointList) { float drawWidth = 0; float drawHeight = 0; boolean shouldLayout = mItemList.size() > 0; mItemList.clear(); for (int i = 0; i < pointList.size(); i++) { float[] line = pointList.get(i); PointF startPoint = new PointF(PtrLocalDisplay.dp2px(line[0]) * mScale, PtrLocalDisplay.dp2px(line[1]) * mScale); PointF endPoint = new PointF(PtrLocalDisplay.dp2px(line[2]) * mScale, PtrLocalDisplay.dp2px(line[3]) * mScale); drawWidth = Math.max(drawWidth, startPoint.x); drawWidth = Math.max(drawWidth, endPoint.x); drawHeight = Math.max(drawHeight, startPoint.y); drawHeight = Math.max(drawHeight, endPoint.y); StoreHouseBarItem item = new StoreHouseBarItem(i, startPoint, endPoint, mTextColor, mLineWidth); item.resetPosition(horizontalRandomness); mItemList.add(item); } mDrawZoneWidth = (int) Math.ceil(drawWidth); mDrawZoneHeight = (int) Math.ceil(drawHeight); if (shouldLayout) { requestLayout(); } } private void beginLoading() { mIsInLoading = true; mAniController.start(); invalidate(); } private void loadFinish() { mIsInLoading = false; mAniController.stop(); } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); float progress = mProgress; int c1 = canvas.save(); int len = mItemList.size(); for (int i = 0; i < mItemList.size(); i++) { canvas.save(); StoreHouseBarItem storeHouseBarItem = mItemList.get(i); float offsetX = mOffsetX + storeHouseBarItem.midPoint.x; float offsetY = mOffsetY + storeHouseBarItem.midPoint.y; if (mIsInLoading) { storeHouseBarItem.getTransformation(getDrawingTime(), mTransformation); canvas.translate(offsetX, offsetY); } else { if (progress == 0) { storeHouseBarItem.resetPosition(horizontalRandomness); continue; } float startPadding = (1 - internalAnimationFactor) * i / len; float endPadding = 1 - internalAnimationFactor - startPadding; // done if (progress == 1 || progress >= 1 - endPadding) { canvas.translate(offsetX, offsetY); storeHouseBarItem.setAlpha(mBarDarkAlpha); } else { float realProgress; if (progress <= startPadding) { realProgress = 0; } else { realProgress = Math.min(1, (progress - startPadding) / internalAnimationFactor); } offsetX += storeHouseBarItem.translationX * (1 - realProgress); offsetY += -mDropHeight * (1 - realProgress); Matrix matrix = new Matrix(); matrix.postRotate(360 * realProgress); matrix.postScale(realProgress, realProgress); matrix.postTranslate(offsetX, offsetY); storeHouseBarItem.setAlpha(mBarDarkAlpha * realProgress); canvas.concat(matrix); } } storeHouseBarItem.draw(canvas); canvas.restore(); } if (mIsInLoading) { invalidate(); } canvas.restoreToCount(c1); } @Override public void onUIReset(PtrFrameLayout frame) { loadFinish(); for (int i = 0; i < mItemList.size(); i++) { mItemList.get(i).resetPosition(horizontalRandomness); } } @Override public void onUIRefreshPrepare(PtrFrameLayout frame) { } @Override public void onUIRefreshBegin(PtrFrameLayout frame) { beginLoading(); } @Override public void onUIRefreshComplete(PtrFrameLayout frame) { loadFinish(); } @Override public void onUIPositionChange(PtrFrameLayout frame, boolean isUnderTouch, byte status, int oldPosition, int currentPosition, float oldPercent, float currentPercent) { // currentPercent = Math.max(1, currentPercent); setProgress(currentPercent); invalidate(); } private class AniController implements Runnable { private int mTick = 0; private int mCountPerSeg = 0; private int mSegCount = 0; private int mInterval = 0; private boolean mRunning = true; private void start() { mRunning = true; mTick = 0; mInterval = mLoadingAniDuration / mItemList.size(); mCountPerSeg = mLoadingAniSegDuration / mInterval; mSegCount = mItemList.size() / mCountPerSeg + 1; run(); } @Override public void run() { int pos = mTick % mCountPerSeg; for (int i = 0; i < mSegCount; i++) { int index = i * mCountPerSeg + pos; if (index > mTick) { continue; } index = index % mItemList.size(); StoreHouseBarItem item = mItemList.get(index); item.setFillAfter(false); item.setFillEnabled(true); item.setFillBefore(false); item.setDuration(mLoadingAniItemDuration); item.start(mFromAlpha, mToAlpha); } mTick++; if (mRunning) { postDelayed(this, mInterval); } } private void stop() { mRunning = false; removeCallbacks(this); } } }