A Drawable that transitions between two child Drawables based on this Drawable's current level value. The idea here is that the center value (5000) will show the 'selected' Drawable, and any other value will show a transitional value between the 'selected' Drawable and the 'unselected' Drawable.
April 3, 2015 ยท View on GitHub
package com.pixite.fragment.widget;
import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable.Callback; import android.view.Gravity;
/**
-
A Drawable that transitions between two child Drawables based on this
-
Drawable's current level value. The idea here is that the center value
-
(5000) will show the 'selected' Drawable, and any other value will show
-
a transitional value between the 'selected' Drawable and the 'unselected'
-
Drawable.
-
Selected Unselected Value=2500 Value=7500
-
|XXXX| | | |XX | | XX|
-
|XXXX| | | |XX | | XX|
-
|XXXX| | | |XX | | XX|
-
Created by rharter on 4/18/14. */ public class RevealDrawable extends Drawable implements Callback {
private RevealState mRevealState; private final Rect mTmpRect = new Rect();
public static final int HORIZONTAL = 1; public static final int VERTICAL = 2;
public RevealDrawable(Drawable unselected, Drawable selected, int orientation) { this(null, null);
mRevealState.mUnselectedDrawable = unselected; mRevealState.mSelectedDrawable = selected; mRevealState.mOrientation = orientation; if (unselected != null) { unselected.setCallback(this); } if (selected != null) { selected.setCallback(this); }}
@Override public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); if (callback != null) { callback.invalidateDrawable(this); } }
@Override public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); if (callback != null) { callback.scheduleDrawable(this, what, when); } }
@Override public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); if (callback != null) { callback.unscheduleDrawable(this, what); } }
@Override public int getChangingConfigurations() { return super.getChangingConfigurations() | mRevealState.mChangingConfigurations | mRevealState.mUnselectedDrawable.getChangingConfigurations() | mRevealState.mSelectedDrawable.getChangingConfigurations(); }
@Override public boolean getPadding(Rect padding) { // XXX need to adjust padding! return mRevealState.mSelectedDrawable.getPadding(padding); }
@Override public boolean setVisible(boolean visible, boolean restart) { mRevealState.mUnselectedDrawable.setVisible(visible, restart); mRevealState.mSelectedDrawable.setVisible(visible, restart); return super.setVisible(visible, restart); }
@Override public void setAlpha(int alpha) {
}
@Override public void setColorFilter(ColorFilter cf) {
}
@Override public int getOpacity() { return 0; }
@Override protected void onBoundsChange(Rect bounds) { mRevealState.mUnselectedDrawable.setBounds(bounds); mRevealState.mSelectedDrawable.setBounds(bounds); }
@Override protected boolean onLevelChange(int level) { mRevealState.mUnselectedDrawable.setLevel(level); mRevealState.mSelectedDrawable.setLevel(level); invalidateSelf(); return true; }
@Override public void draw(Canvas canvas) {
// If level == 10000 || level == 0, just draw the unselected image int level = getLevel(); if (level == 10000 || level == 0) { mRevealState.mUnselectedDrawable.draw(canvas); } // If level == 5000 just draw the selected image else if (level == 5000) { mRevealState.mSelectedDrawable.draw(canvas); } // Else, draw the transitional version else { final Rect r = mTmpRect; final Rect bounds = getBounds(); { // Draw the unselected portion float value = (level / 5000f) - 1f; int w = bounds.width(); if ((mRevealState.mOrientation & HORIZONTAL) != 0) { w = (int) (w * Math.abs(value)); } int h = bounds.height(); if ((mRevealState.mOrientation & VERTICAL) != 0) { h = (int) (h * Math.abs(value)); } int gravity = value < 0 ? Gravity.LEFT : Gravity.RIGHT; Gravity.apply(gravity, w, h, bounds, r); if (w > 0 && h > 0) { canvas.save(); canvas.clipRect(r); mRevealState.mUnselectedDrawable.draw(canvas); canvas.restore(); } } { // Draw the selected portion float value = (level / 5000f) - 1f; int w = bounds.width(); if ((mRevealState.mOrientation & HORIZONTAL) != 0) { w -= (int) (w * Math.abs(value)); } int h = bounds.height(); if ((mRevealState.mOrientation & VERTICAL) != 0) { h -= (int) (h * Math.abs(value)); } int gravity = value < 0 ? Gravity.RIGHT : Gravity.LEFT; Gravity.apply(gravity, w, h, bounds, r); if (w > 0 && h > 0) { canvas.save(); canvas.clipRect(r); mRevealState.mSelectedDrawable.draw(canvas); canvas.restore(); } } }}
@Override public int getIntrinsicWidth() { return Math.max(mRevealState.mSelectedDrawable.getIntrinsicWidth(), mRevealState.mUnselectedDrawable.getIntrinsicWidth()); }
@Override public int getIntrinsicHeight() { return Math.max(mRevealState.mSelectedDrawable.getIntrinsicHeight(), mRevealState.mUnselectedDrawable.getIntrinsicHeight()); }
@Override public ConstantState getConstantState() { if (mRevealState.canConstantState()) { mRevealState.mChangingConfigurations = getChangingConfigurations(); return mRevealState; } return null; }
final static class RevealState extends ConstantState { Drawable mSelectedDrawable; Drawable mUnselectedDrawable; int mChangingConfigurations; int mOrientation;
private boolean mCheckedConstantState; private boolean mCanConstantState; RevealState(RevealState orig, RevealDrawable owner, Resources res) { if (orig != null) { if (res != null) { mSelectedDrawable = orig.mSelectedDrawable.getConstantState().newDrawable(res); mUnselectedDrawable = orig.mUnselectedDrawable.getConstantState().newDrawable(res); } else { mSelectedDrawable = orig.mSelectedDrawable.getConstantState().newDrawable(); mUnselectedDrawable = orig.mUnselectedDrawable.getConstantState().newDrawable(); } mSelectedDrawable.setCallback(owner); mUnselectedDrawable.setCallback(owner); mOrientation = orig.mOrientation; mCheckedConstantState = mCanConstantState = true; } } @Override public Drawable newDrawable() { return new RevealDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { return new RevealDrawable(this, res); } @Override public int getChangingConfigurations() { return mChangingConfigurations; } boolean canConstantState() { if (!mCheckedConstantState) { mCanConstantState = mSelectedDrawable.getConstantState() != null && mUnselectedDrawable.getConstantState() != null; mCheckedConstantState = true; } return mCanConstantState; }}
private RevealDrawable(RevealState state, Resources res) { mRevealState = new RevealState(state, this, res); } }