5

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!

Zez3
  • 259
  • 3
  • 12

2 Answers2

8

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 bgCirclePaintand 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:

2

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 RadialProgressViewis 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 ;)

Community
  • 1
  • 1
Felix Alcala
  • 2,837
  • 3
  • 27
  • 31
  • can we change only center part of the ring ? – SARATH SASI Aug 06 '15 at 05:16
  • @SarathiOS: I'm not sure I understand your question. Which part would you like to change, too? – Felix Alcala Aug 06 '15 at 08:13
  • the view around that Label (40) that view i have to change. Is it possible ? – SARATH SASI Aug 06 '15 at 15:12
  • @SarathiOS: I've added two more color setters. Basically, you need to set the BorderColor back to anything that you'd like, and also the ProgressBackgroundColor. So by setting all four colors to new values it's possible. There's one limitation: at the very outside of the circle you'll get a very slim (1px?) border of the CircleColor, under any circumstances. So it would be best to pick colors that hide this this, like I did. – Felix Alcala Aug 06 '15 at 17:57
  • Thaks for you time and reply – SARATH SASI Aug 07 '15 at 05:32
1

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

Mina Wissa
  • 10,923
  • 13
  • 90
  • 158
  • i have implemented this radial Progress View in my ios App. But unfortunately i didn't find any option to change its background. Inner area. I have to Change its background to White – SARATH SASI Jul 30 '15 at 10:26
  • You have any idea to change the back ground of Radial Progress view. Thanks in advance – SARATH SASI Jul 30 '15 at 10:28
  • I believe you have to access the underlying components and change their properties, in Android if you can cast the RadialProgressView to a ViewGroup, you can access the children via getChildAt(int index) method. – Mina Wissa Jul 30 '15 at 11:58
  • @SARATH Can you please post your iOS solution? – LCJ Aug 08 '17 at 16:42
  • @Lijo https://stackoverflow.com/questions/31693428/drawing-circles-in-xamarin-ios-xamarin-monotouch-for-showing-progress-graphica you can use this solution – SARATH SASI Aug 09 '17 at 04:37