3

I used inputs from this SO Question to create a custom progress-bar with rounded corners for the Android platform using the Drawable. But the I'm not able to create the same output for the iOS.

Given below is how it looks on Android. Android Sample

How can I create the same effect in the iOS as well?

Community
  • 1
  • 1
Libin TK
  • 1,477
  • 2
  • 25
  • 46

1 Answers1

5

There are a number of ways to do this, I prefer using the CALayer of a UIView and adding a CAShapeLayer that draws the "progress bar".

UIView ProgressBar Example:

enter image description here

public class ProgressView : UIView
{
    CAShapeLayer progressLayer;
    UILabel label;

    public ProgressView() { Setup(); }
    public ProgressView(Foundation.NSCoder coder) : base(coder) { Setup(); }
    public ProgressView(Foundation.NSObjectFlag t) : base(t) { Setup(); }
    public ProgressView(IntPtr handle) : base(handle) { }
    public ProgressView(CGRect frame) : base(frame) { Setup(); }

    void Setup()
    {
        BackgroundColor = UIColor.Clear;

        Layer.CornerRadius = 25;
        Layer.BorderWidth = 10;
        Layer.BorderColor = UIColor.Blue.CGColor;
        Layer.BackgroundColor = UIColor.Cyan.CGColor;

        progressLayer = new CAShapeLayer()
        {
            FillColor = UIColor.Red.CGColor,
            Frame = Bounds
        };
        Layer.AddSublayer(progressLayer);

        label = new UILabel(Bounds)
        {
            TextAlignment = UITextAlignment.Center,
            TextColor = UIColor.White,
            BackgroundColor = UIColor.Clear,
            Font = UIFont.FromName("ChalkboardSE-Bold", 20)
        };
        InsertSubview(label, 100);
    }

    double complete;
    public double Complete
    {
        get { return complete; }
        set { complete = value; label.Text = $"{value * 100} %"; SetNeedsDisplay(); }
    }

    public override void Draw(CGRect rect)
    {
        base.Draw(rect);
        var progressWidth = (rect.Width - (Layer.BorderWidth * 2)) * complete;
        var progressRect = new CGRect(rect.X + Layer.BorderWidth, rect.Y + Layer.BorderWidth, progressWidth, (rect.Height - Layer.BorderWidth * 2));
        progressLayer.Path = UIBezierPath.FromRoundedRect(progressRect, 25).CGPath;
    }
}

Usage Example:

var progressView = new ProgressView(new CGRect(50, 50, 300, 50));
Add(progressView);
DispatchQueue.MainQueue.DispatchAsync(async () =>
{
    while (progressView.Complete <= 1)
    {
        InvokeOnMainThread(() => progressView.Complete += 0.05);
        await Task.Delay(1000);
    }
});
SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • thank you for the detailed answer. Could you also help me with how to implement this method using a `CustomRenderer` or with `Xamarin.Forms`?. – Libin TK Feb 05 '18 at 07:36
  • @LibinTK Xamarin has a guide that shows how to implemented a custom view renderer for Forms: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/view/ – SushiHangover Feb 05 '18 at 08:55
  • How to display same UI in android? – Yalamandarao Sep 19 '18 at 13:48
  • @Singapore Ask a new question with the code that you have so far and your issue. – SushiHangover Sep 19 '18 at 14:07
  • @SushiHangoverThanks for this answer. I have used your answer to make a progress bar which starts from the right. `var progressWidth = (rect.Width - (Layer.BorderWidth * 2)) * (1 - complete); var progressRect = new CGRect(rect.X + progressWidth, rect.Y + Layer.BorderWidth, rect.Width - progressWidth, (rect.Height - Layer.BorderWidth * 2)); progressLayer.Path = UIBezierPath.FromRoundedRect(progressRect, (UIRectCorner.TopRight | UIRectCorner.BottomRight), new CGSize(30, 30)).CGPath; ` But I don't see the label. – Katana Oct 22 '18 at 21:40
  • @Naman You should create a new question with the code you are using and the problem you are having – SushiHangover Oct 22 '18 at 21:42
  • @SushiHangover I posted another question https://stackoverflow.com/questions/52938246/reverse-progress-bar-in-xamarin-forms – Katana Oct 22 '18 at 21:52