I've made a custom pie chart view that I want to animate starting when the pie chart is visible. Currently what I have is the pie chart animating but by the time you can actually see it on the screen the animation is half over. This is what I have:
public class SinglePieChart extends SurfaceView implements SurfaceHolder.Callback {
// Chart setting variables
private int emptyCircleCol, strokeColor, number, total;
// Paint for drawing custom view
private Paint circlePaint;
private RectF rect;
private Context context;
private AnimThread animThread;
private SurfaceHolder holder;
// animation variables
private float speed;
private float current = 0.0f;
private boolean percentsCalculated = false;
private float degree;
private int viewWidth, viewHeight;
public SinglePieChart(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
context = ctx;
// Paint object for drawing in doDraw
circlePaint = new Paint();
circlePaint.setStyle(Style.STROKE);
circlePaint.setStrokeWidth(3);
circlePaint.setAntiAlias(true);
circlePaint.setDither(true);
rect = new RectF();
//get the attributes specified in attrs.xml using the name we included
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.DashboardChartSmall, 0, 0);
try {
//get the colors specified using the names in attrs.xml
emptyCircleCol = a.getColor(R.styleable.DashboardChartSmall_smCircleColor, 0xFF65676E); // light gray is default
strokeColor = a.getColor(R.styleable.DashboardChartSmall_smColor, 0xFF39B54A); // green is default
// Default number values
total = a.getInteger(R.styleable.DashboardChartSmall_smTotal, 1);
number = a.getInteger(R.styleable.DashboardChartSmall_smNumber, 0);
} finally {
a.recycle();
}
this.setZOrderOnTop(true);
holder = getHolder();
holder.setFormat(PixelFormat.TRANSPARENT);
holder.addCallback(this);
}
protected void calculateValues() {
degree = 360 * number / total;
percentsCalculated = true;
speed = 10 * number / total;
viewWidth = this.getMeasuredWidth();
viewHeight = this.getMeasuredHeight();
float top, left, bottom, right;
if (viewWidth < viewHeight) {
left = 4;
right = viewWidth - 4;
top = ((viewHeight - viewWidth) / 2) + 4;
bottom = viewHeight - top;
} else {
top = 4;
bottom = viewHeight - 4;
left = ((viewWidth - viewHeight) / 2) + 4;
right = viewWidth - left;
}
rect.set(left, top, right, bottom);
}
protected void doDraw(Canvas canvas) {
if (total == 0) {
// Number values are not ready
animThread.setRunning(false);
return;
}
if (!percentsCalculated) {
calculateValues();
}
// set the paint color using the circle color specified
float last = current;
float start = -90;
circlePaint.setColor(strokeColor);
canvas.drawArc(rect, start, (last > degree) ? degree : last, false, circlePaint);
start += (last > number) ? number : last;
last = (last < number) ? 0 : last - number;
circlePaint.setColor(emptyCircleCol);
if (current > 360) {
current = 360;
}
canvas.drawArc(rect, start, 360 - current, false, circlePaint);
current += speed;
if (last > 0 || number == 0) {
// we're done
animThread.setRunning(false);
}
}
public void setNumbers(int num, int tot) {
number = num;
total = tot;
invalidate();
requestLayout();
}
public void setColor(int col) {
strokeColor = col;
}
public void redraw() {
calculateValues();
animThread.setRunning(true);
invalidate();
requestLayout();
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
animThread = new AnimThread(holder, context, this);
animThread.setRunning(true);
animThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
animThread.setRunning(false);
boolean retry = true;
while(retry) {
try {
animThread.join();
retry = false;
} catch(Exception e) {
Log.v("Exception Occured", e.getMessage());
}
}
}
public class AnimThread extends Thread {
boolean mRun;
Canvas mcanvas;
SurfaceHolder surfaceHolder;
Context context;
SinglePieChart msurfacePanel;
public AnimThread(SurfaceHolder sholder, Context ctx, SinglePieChart spanel) {
surfaceHolder = sholder;
context = ctx;
mRun = false;
msurfacePanel = spanel;
}
void setRunning(boolean bRun) {
mRun = bRun;
}
@Override
public void run() {
super.run();
while (mRun) {
mcanvas = surfaceHolder.lockCanvas();
if (mcanvas != null) {
msurfacePanel.doDraw(mcanvas);
surfaceHolder.unlockCanvasAndPost(mcanvas);
}
}
}
}
}
Also if you see any programming errors, memory leaks, poor performing code, please let me know. I'm new to Android.
Here is the layout that uses the SinglePieChart class:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.davidscoville.vokab.views.elements.SinglePieChart
android:id="@+id/smallPieChart"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/dashSmNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:textSize="25sp"
android:textColor="#FFFFFF" />
</RelativeLayout>
<TextView
android:id="@+id/dashSmLabel"
android:layout_width="match_parent"
android:layout_height="20dp"
android:textSize="14sp"
android:gravity="center"
android:textColor="#FFFFFF" />
</merge>