Last active
August 29, 2015 14:22
-
-
Save Tagakov/37f59f83721a1893f5d6 to your computer and use it in GitHub Desktop.
Example of clipPath like behavior with use of BItmapShader.
This file contains 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.tagakov.testapplication; | |
import android.animation.ValueAnimator; | |
import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.graphics.BitmapShader; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.graphics.RectF; | |
import android.graphics.Shader; | |
import android.os.Build; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.view.animation.AccelerateDecelerateInterpolator; | |
/** | |
* Created by tagakov on 28.05.15. | |
*/ | |
public class SectorClipProgress extends View implements ValueAnimator.AnimatorUpdateListener { | |
private final ValueAnimator valueAnimator = ValueAnimator.ofFloat(); | |
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); | |
private final int foregroundResource; | |
private float sweepAngle; | |
private RectF rectF; | |
public SectorClipProgress(Context context, int backgroundResource, int foregroundResource) { | |
super(context); | |
setBackgroundResource(backgroundResource); | |
this.foregroundResource = foregroundResource; | |
init(); | |
} | |
public SectorClipProgress(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
foregroundResource = getForegroundResId(attrs); | |
init(); | |
} | |
public SectorClipProgress(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
foregroundResource = getForegroundResId(attrs); | |
init(); | |
} | |
@TargetApi(Build.VERSION_CODES.LOLLIPOP) | |
public SectorClipProgress(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | |
super(context, attrs, defStyleAttr, defStyleRes); | |
foregroundResource = getForegroundResId(attrs); | |
init(); | |
} | |
private void init() { | |
if (getResources().getResourceName(foregroundResource) == null) { | |
throw new IllegalStateException("You should provide foreground drawable for SectorClipProgress view!"); | |
} | |
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); | |
valueAnimator.addUpdateListener(this); | |
} | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
super.onSizeChanged(w, h, oldw, oldh); | |
rectF = new RectF(0,0,w,h); | |
BitmapShader bs = new BitmapShader(decodeScaledBitmapFromResource(foregroundResource), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); | |
paint.setShader(bs); | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
canvas.drawArc(rectF, -90, sweepAngle, true, paint); | |
} | |
public void start(int duration) { | |
if (valueAnimator.isRunning()) | |
valueAnimator.cancel(); | |
valueAnimator.setDuration(duration); | |
valueAnimator.setFloatValues(0f, 360f); | |
valueAnimator.start(); | |
} | |
public void stop() { | |
if (valueAnimator.isRunning()) { | |
valueAnimator.cancel(); | |
valueAnimator.setFloatValues(sweepAngle, 0); | |
valueAnimator.setDuration(300); | |
valueAnimator.start(); | |
} | |
} | |
@Override | |
public void onAnimationUpdate(ValueAnimator animation) { | |
sweepAngle = (float) animation.getAnimatedValue(); | |
invalidate(); | |
} | |
private int getForegroundResId(AttributeSet attrs) { | |
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.SectorClipProgress); | |
int foregroundId = a.getResourceId(R.styleable.SectorClipProgress_foreground, -1); | |
a.recycle(); | |
return foregroundId; | |
} | |
private Bitmap decodeScaledBitmapFromResource(int resId) { | |
// First decode with inJustDecodeBounds=true to check dimensions | |
final BitmapFactory.Options options = new BitmapFactory.Options(); | |
options.inJustDecodeBounds = true; | |
BitmapFactory.decodeResource(getResources(), resId, options); | |
// Calculate inSampleSize | |
options.inSampleSize = calculateInSampleSize(options); | |
// Decode bitmap with inSampleSize set | |
options.inJustDecodeBounds = false; | |
Bitmap tmp = BitmapFactory.decodeResource(getResources(), resId, options); | |
Bitmap result = Bitmap.createScaledBitmap(tmp, getWidth(), getHeight(), true); | |
tmp.recycle(); | |
return result; | |
} | |
private int calculateInSampleSize(BitmapFactory.Options options) { | |
// Raw height and width of image | |
final int height = options.outHeight; | |
final int width = options.outWidth; | |
int reqHeight = getHeight(); | |
int reqWidth = getWidth(); | |
int inSampleSize = 1; | |
if (height > reqHeight || width > reqWidth) { | |
final int halfHeight = height / 2; | |
final int halfWidth = width / 2; | |
// Calculate the largest inSampleSize value that is a power of 2 and keeps both | |
// height and width larger than the requested height and width. | |
while ((halfHeight / inSampleSize) > reqHeight | |
&& (halfWidth / inSampleSize) > reqWidth) { | |
inSampleSize *= 2; | |
} | |
} | |
return inSampleSize; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment