Skip to content

Instantly share code, notes, and snippets.

@Tagakov
Last active August 29, 2015 14:22
Show Gist options
  • Save Tagakov/37f59f83721a1893f5d6 to your computer and use it in GitHub Desktop.
Save Tagakov/37f59f83721a1893f5d6 to your computer and use it in GitHub Desktop.
Example of clipPath like behavior with use of BItmapShader.
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