I 've been trying to implement the RadialProgress component (https://components.xamarin.com/view/radialprogress) on my app. I managed to get it on the screen, and change the progress colour but I can't find a way to change the inner colour of the circle.
The RadialProgressView object itself has a BackgroundTintMode field which takes a DuffPorter.Mode but whenever I try to set the background tint mode the app breaks with this message (Message = "no method with name='setBackgroundTintMode' signature='(Landroid/graphics/PorterDuff$Mode;))
Is there even a way to do what I want?
Thanks!
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 ;)
You can try implementing a custom ViewRenderer and access the underlying native Android views to modify them as you want. https://blog.xamarin.com/using-custom-controls-in-xamarin.forms-on-android/
The error you have regarding the "setBackgroundTintMode" method indicates that you may need to update your Xamarin platform to make sure that the latest APIs are available
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With