Yes, it can be done. Although not in a very straight-forward way or even maintainable way.
Firstly, let's dig a little into RadialProgressView
's drawing code (as exposed by Xamarin Studio Assembly Browser):
protected override void OnDraw(Canvas canvas)
{
// ... there's more stuff here, but you get the idea
canvas.DrawCircle(this.bgCx, this.bgCy, this.radius, this.bgCirclePaint);
canvas.DrawCircle(this.bgCx, this.bgCy, this.innerLineRadius, this.bgBorderPaint);
canvas.DrawText(this.valueText, this.textX, this.textY, this.textPaint);
}
We notice some colors here, like bgCirclePaint
and bgBorderPaint
. If we are able to change the value of these variables, we will be able to change the color with which the ProgressView is painted.
The problem is that RadialProgressView
does not expose the fields – they are all private, so simply inheriting from RadialProgressView
will not allow us to set them to a new value.
However, we can make use of reflection to change these private fields, like so:
var textPaintMember = typeof(RadialProgressView).GetField("textPaint", BindingFlags.Instance | BindingFlags.NonPublic);
textPaintMember.SetValue(Instance, MyNewSuperCoolColorPaint);
By combining the two, we can come up with a new, customizable class like this:
public class CustomizableRadialProgressView : RadialProgressView
{
public CustomizableRadialProgressView(Context context) : base(context)
{
}
public void SetTextColor(Color color)
{
var paint = new Paint();
paint.SetTypeface(Typeface.DefaultBold);
paint.Color = color;
paint.AntiAlias = true;
var textPaintMember = typeof(RadialProgressView).GetField("textPaint", BindingFlags.Instance | BindingFlags.NonPublic);
textPaintMember.SetValue(this, paint);
}
public void SetCircleColor(Color color)
{
var paint = new Paint();
paint.SetStyle(Paint.Style.Fill);
paint.Color = color;
paint.AntiAlias = true;
var circlePaintMember = typeof(RadialProgressView).GetField("bgCirclePaint", BindingFlags.Instance | BindingFlags.NonPublic);
circlePaintMember.SetValue(this, paint);
}
public void SetBorderColor(Color color)
{
var paint = new Paint();
paint.SetStyle(Paint.Style.Stroke);
paint.Color = color;
paint.AntiAlias = true;
var circlePaintMember = typeof(RadialProgressView).GetField("bgBorderPaint", BindingFlags.Instance | BindingFlags.NonPublic);
circlePaintMember.SetValue(this, paint);
}
public void SetProgressPackgroundColor(Color color)
{
var paint = new Paint();
paint.SetStyle(Paint.Style.Stroke);
paint.Color = color;
paint.AntiAlias = true;
var circlePaintMember = typeof(RadialProgressView).GetField("bgProgressPaint", BindingFlags.Instance | BindingFlags.NonPublic);
circlePaintMember.SetValue(this, paint);
}
}
This will get us the result we're after:

Note: It is probably wise to notice that we are making improper use of private fields: We're manipulating them from outside of the class they live in. If Xamarin ever decides to change the way RadialProgressView
is implemented, or even only renames one of the private variables, our code will fail at runtime. The better way to approach this problem would probably be to just ask Xamarin to provide the getters/setters you need. But, hey, it's SO much cooler this way ;)