Creating a UIProgressView Rounded Corners

I created a UIProgressView with the following properties

 progressView.progressTintColor = UIColor.appChallengeColorWithAlpha(1.0) progressView.trackTintColor = UIColor.clearColor() progressView.clipsToBounds = true progressView.layer.cornerRadius = 5 

I use UIView for the border. He looks like his progress = 1, which is exactly what I want.

enter image description here

But if the value of progress is less than 1. Angles are not rounded, as it should be.

enter image description here

Am I missing something? How can I make this a rounded corner?

+7
source share
12 answers

After searching and trying, I decided to create my own personal view of progress. Here is the code for those who can find them in the same problem.

 import Foundation import UIKit class CustomHorizontalProgressView: UIView { var progress: CGFloat = 0.0 { didSet { setProgress() } } override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } func setup() { self.backgroundColor = UIColor.clearColor() } override func drawRect(rect: CGRect) { super.drawRect(rect) setProgress() } func setProgress() { var progress = self.progress progress = progress > 1.0 ? progress / 100 : progress self.layer.cornerRadius = CGRectGetHeight(self.frame) / 2.0 self.layer.borderColor = UIColor.grayColor().CGColor self.layer.borderWidth = 1.0 let margin: CGFloat = 6.0 var width = (CGRectGetWidth(self.frame) - margin) * progress let height = CGRectGetHeight(self.frame) - margin if (width < height) { width = height } let pathRef = UIBezierPath(roundedRect: CGRect(x: margin / 2.0, y: margin / 2.0, width: width, height: height), cornerRadius: height / 2.0) UIColor.redColor().setFill() pathRef.fill() UIColor.clearColor().setStroke() pathRef.stroke() pathRef.closePath() self.setNeedsDisplay() } } 

Just add the code to the fast file and drag the UIView to IB and give it the CustomHorizontalProgressView class. and it's all.

+5
source

UIProgressView has two parts, part progress and part track. If you use Reveal, you can see that it has only two subtitles. The hierarchy of representations of progress is very simple. so that...

Objective-c

 - (void)layoutSubviews { [super layoutSubviews]; [self.progressView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { obj.layer.masksToBounds = YES; obj.layer.cornerRadius = kProgressViewHeight / 2.0; }]; } 

Swift 3

 override func layoutSubviews() { super.layoutSubviews() subviews.forEach { subview in subview.layer.masksToBounds = true subview.layer.cornerRadius = kProgressViewHeight / 2.0 } } 

I acknowledge that subclassing or advanced progress is the recommended way. In case you do not want to do this for such a simple effect, this can do the trick. Keep the situation when Apple changes the hierarchy of views, and something may go wrong.

+15
source

Yes, one thing is missing ... The corner radius is set to progressview, and it reflects as expected.

But if you want your track image to be rounded, you need to adjust your progress. You must use a rounded image.

 [progressView setTrackImage:[UIImage imageNamed:@"roundedTrack.png"]]; //roundedTrack.png must be of rounded corner 

This code above will help you modify the trackView image for your progress.

You may experience inappropriate image stretching. You have to make your image mutable. Maybe the link below will be useful if there is a problem https://www.natashatherobot.com/ios-stretchable-button-uiedgeinsetsmake/

+2
source
 class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let v = ProgessView(frame: CGRect(x: 20, y: 200, width: 100, height: 10)) view.addSubview(v) //v.progressLayer.strokeEnd = 0.8 } } class ProgessView: UIView { lazy var progressLayer: CAShapeLayer = { let line = CAShapeLayer() let path = UIBezierPath() path.move(to: CGPoint(x: 5, y: 5)) path.addLine(to: CGPoint(x: self.bounds.width - 5, y: 5)) line.path = path.cgPath line.lineWidth = 6 line.strokeColor = UIColor(colorLiteralRed: 127/255, green: 75/255, blue: 247/255, alpha: 1).cgColor line.strokeStart = 0 line.strokeEnd = 0.5 line.lineCap = kCALineCapRound line.frame = self.bounds return line }() override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.white layer.cornerRadius = 5 layer.borderWidth = 1 layer.borderColor = UIColor(colorLiteralRed: 197/255, green: 197/255, blue: 197/255, alpha: 1).cgColor layer.addSublayer(progressLayer) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 

Check out my codes. You can design the height and width as you wish. You can use strokeEnd to change the progressView progress. You can add animation to it. But in fact, it is already animated, you can change the value of strokeEnd to see its main effect. If you want to create your own animation. Try CATransaction as shown below.

 func updateProgress(_ progress: CGFloat) { CATransaction.begin() CATransaction.setAnimationDuration(3) progressLayer.strokeEnd = progress CATransaction.commit() } 
+2
source

Just do it in init

  layer.cornerRadius = *desired_corner_radius* clipsToBounds = true 
+1
source

Basically, subviews of viewing progress (default style) consist of two images. One for "progress" and the other for "track". You can loop the subviews of the progress view and set each radius of the image viewing angle.

 for let view: UIView in self.progressView.subviews { if view is UIImageView { view.clipsToBounds = true view.layer.cornerRadius = 15 } } 
+1
source

It's too late to answer, but actually I had the same problem.

Here is my simplest solution (no code needed!):

  1. Add a container to embed your progress

Container

  1. Round corner for your container (10 = container height / 2)

Roundcorner

  1. Result :)

Tada!

+1
source

I had the same problem and it led me to your question after it looked like crazy. The problem is twofold. First, how to make the inside of the progress bar at the end (which 季 亨达 the answer shows how to do it), and secondly, how to make the round end of the CAShapeLayer you add coincide with the square end of the original progress bar (the answer to this other StackOverflow question helped with this How to get the exact point of objects in swift? ) If you replace this line of code with the 季 亨达 answer:

path.addLine (to: CGPoint (x: self.bounds.width - 5, y: 5))

with this:

path.addLine (to: CGPoint (x: (Int (self.progress * Float (self.bounds.width))), y: 5))

you hopefully get the result you are looking for.

0
source

With swift 4.0, I do this:

 let progressViewHeight: CGFloat = 4.0 // Set progress view height let transformScale = CGAffineTransform(scaleX: 1.0, y: progressViewHeight) self.progressView.transform = transformScale // Set progress round corners self.progressView.layer.cornerRadius = progressViewHeight self.progressView.clipsToBounds = true 
0
source

// Updated for Swift 4

 import Foundation import UIKit class CustomHorizontalProgressView: UIView { var progress: CGFloat = 0.0 { didSet { setProgress() } } override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } func setup() { self.backgroundColor = UIColor.clear } override func draw(_ rect: CGRect) { super.draw(rect) setProgress() } func setProgress() { var progress = self.progress progress = progress > 1.0 ? progress / 100 : progress self.layer.cornerRadius = self.frame.height / 2.0 self.layer.borderColor = UIColor.gray.cgColor self.layer.borderWidth = 1.0 let margin: CGFloat = 6.0 var width = (self.frame.width - margin) * progress let height = self.frame.height - margin if (width < height) { width = height } let pathRef = UIBezierPath(roundedRect: CGRect(x: margin / 2.0, y: margin / 2.0, width: width, height: height), cornerRadius: height / 2.0) UIColor.red.setFill() pathRef.fill() UIColor.clear.setStroke() pathRef.stroke() pathRef.close() self.setNeedsDisplay() } } 
0
source

Swift 4.2 from Umair Afzal

 class CustomHorizontalProgressView: UIView { var strokeColor: UIColor? var progress: CGFloat = 0.0 { didSet { setNeedsDisplay() } } override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } func setup() { self.backgroundColor = UIColor.clear } override func draw(_ rect: CGRect) { super.draw(rect) setProgress() } func setProgress() { var progress = self.progress progress = progress > 1.0 ? progress / 100 : progress self.layer.cornerRadius = frame.size.height / 2.0 self.layer.borderColor = UIColor.gray.cgColor self.layer.borderWidth = 1.0 let margin: CGFloat = 6.0 var width = (frame.size.width - margin) * progress let height = frame.size.height - margin if (width < height) { width = height } let pathRef = UIBezierPath(roundedRect: CGRect(x: margin / 2.0, y: margin / 2.0, width: width, height: height), cornerRadius: height / 2.0) strokeColor?.setFill() pathRef.fill() UIColor.clear.setStroke() pathRef.stroke() pathRef.close() } } 

And use it

 var progressView: CustomHorizontalProgressView = { let view = CustomHorizontalProgressView() view.strokeColor = UIColor.orange view.progress = 0.5 return view }() 
0
source

Set the line limit:

.lineCap = kCALineCapRound;

-1
source

Source: https://habr.com/ru/post/1260685/


All Articles