Created
April 3, 2015 17:41
-
-
Save rharter/34051da57f8a6a0991ff to your computer and use it in GitHub Desktop.
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.
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 characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
please give a sample,thanks