Created
November 28, 2013 13:19
-
-
Save AnderWeb/7691721 to your computer and use it in GitHub Desktop.
Revisions
-
AnderWeb created this gist
Nov 28, 2013 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,255 @@ /* * Copyright (C) 2013 AnderWeb (Gustavo Claramunt) * * Inspiration from http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ public class ScrollDrawable extends Drawable implements Animatable { public static class Builder { private Drawable drawable; private Interpolator interpolator; private long duration; private float scale; public Builder(Drawable wrapped) { this.drawable = wrapped; } public Builder setDuration(long durationMillis) { this.duration = durationMillis; return this; } public Builder setInterpolator(Interpolator interpolator) { this.interpolator = interpolator; return this; } /** * This is where you set the difference between the drawable height and the total scroll height. * So if this has a height of 300 and the scale is 1.5f, you'll get a 450px image scrolling up and down * * Note: this doesn't take proportions into consideration, so images may result stretched and/or ugly :) * * @param scrollScale the difference between this drawable height and the scrollable height. * Values <1f are ignored. * @return the instance of this Builder. */ public Builder setScrollScale(float scrollScale) { this.scale = scrollScale; return this; } public ScrollDrawable build() { return new ScrollDrawable(drawable, interpolator, duration, scale); } } private static final long FRAME_DURATION = 1000 / 60; private float mScrollOffset; private float mScrollScale; private long mScrollDuration; private Interpolator mInterpolator; private Drawable mWrapped; private final Rect mBounds = new Rect(); private int mScrollHeight; private long mStartTime; private boolean mReverse = false; private boolean mRunning = false; private ScrollDrawable(Drawable wrapped, Interpolator interpolator, long duration, float scale) { mWrapped = wrapped; mInterpolator = interpolator != null ? interpolator : new AccelerateDecelerateInterpolator(); mScrollDuration = duration > 0 ? duration : 4000; mScrollScale = scale > 1f ? scale : 1.5f; } @Override public void draw(Canvas canvas) { canvas.clipRect(mBounds); float currentScroll = mScrollOffset * mScrollHeight; canvas.translate(0, -currentScroll); mWrapped.draw(canvas); canvas.translate(0, currentScroll); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mBounds.set(bounds); int scrollSize = (int) (bounds.height() * mScrollScale); mScrollHeight = scrollSize - bounds.height(); mWrapped.setBounds(bounds.left, bounds.top, bounds.right, bounds.top + scrollSize); } private final Runnable mUpdater = new Runnable() { @Override public void run() { long currentTime = SystemClock.uptimeMillis(); long diff = currentTime - mStartTime; if (diff < mScrollDuration) { float interpolation = mInterpolator.getInterpolation((float) diff / (float) mScrollDuration); if (mReverse) { interpolation = 1f - interpolation; } mScrollOffset = interpolation; } else { //Reverse! mReverse = !mReverse; mStartTime = currentTime; } scheduleSelf(mUpdater, currentTime + FRAME_DURATION); invalidateSelf(); } }; @Override public void start() { if (isRunning()) return; mRunning = true; mStartTime = SystemClock.uptimeMillis(); scheduleSelf(mUpdater, mStartTime + FRAME_DURATION); invalidateSelf(); } @Override public void stop() { if (!isRunning()) return; unscheduleSelf(mUpdater); mRunning = false; } @Override public boolean isRunning() { return mRunning; } //Rest of Drawable methods redirect to the wrapped drawable @Override public int getIntrinsicWidth() { return mWrapped.getIntrinsicWidth(); } @Override public int getIntrinsicHeight() { return mWrapped.getIntrinsicHeight(); } @Override public int getMinimumWidth() { return mWrapped.getMinimumWidth(); } @Override public int getMinimumHeight() { return mWrapped.getMinimumHeight(); } @Override public boolean getPadding(Rect padding) { return mWrapped.getPadding(padding); } @Override public ConstantState getConstantState() { return super.getConstantState(); } @Override public void setChangingConfigurations(int configs) { mWrapped.setChangingConfigurations(configs); } @Override public int getChangingConfigurations() { return mWrapped.getChangingConfigurations(); } @Override public void setDither(boolean dither) { mWrapped.setDither(dither); } @Override public void setFilterBitmap(boolean filter) { mWrapped.setFilterBitmap(filter); } @Override public void setAlpha(int alpha) { mWrapped.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mWrapped.setColorFilter(cf); } @Override public void setColorFilter(int color, PorterDuff.Mode mode) { mWrapped.setColorFilter(color, mode); } @Override public void clearColorFilter() { mWrapped.clearColorFilter(); } @Override public boolean isStateful() { return mWrapped.isStateful(); } @Override public boolean setState(int[] stateSet) { return mWrapped.setState(stateSet); } @Override public int[] getState() { return mWrapped.getState(); } @Override public Drawable getCurrent() { return mWrapped.getCurrent(); } @Override public boolean setVisible(boolean visible, boolean restart) { return super.setVisible(visible, restart); } @Override public int getOpacity() { return mWrapped.getOpacity(); } @Override public Region getTransparentRegion() { return mWrapped.getTransparentRegion(); } @Override protected boolean onStateChange(int[] state) { mWrapped.setState(state); return super.onStateChange(state); } }