制作UIProgressView圆角

时间:2016-12-02 05:34:32

标签: ios swift uiprogressview

我创建了一个UIProgressView,其中包含以下属性

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

我正在使用UIView作为边框。看起来他的进步= 1,这正是我想要的方式。

enter image description here

但是如果进度值小于1.角落不应该是圆形的。

enter image description here

我错过了什么吗?我怎样才能圆角?

13 个答案:

答案 0 :(得分:15)

UIProgressView有两部分,进度部分和轨道部分。如果您使用Reveal,则可以看到它只有两个子视图。进度视图层次结构非常简单。所以...

<强>目标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
    }
}

我承认子类或扩展进度视图是推荐的方法。如果你不想为这么简单的效果做到这一点,这可能会有所帮助。 保持 Apple将改变视图层次结构的情况,并且可能会出现问题

答案 1 :(得分:5)

搜索并尝试后,我决定创建自己的自定义进度视图。以下是可能在相同问题中找到selevs的任何人的代码。

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()
}
}

将上面的代码放在swift文件中,然后在IB中拖放UIView并将其赋予类CustomHorizontalProgressView。就是这样。

答案 2 :(得分:2)

是的,有一件事是错过的...角半径设置为进度视图,它正如预期的那样反映..

但是如果您想要对您的曲目图像进行舍入,则必须自定义您的进度视图。 你必须使用带圆角的图像。

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

以上代码将帮助您更改trackView的图像以获取进度视图。

您可能会遇到图像不适当的拉伸。您必须使图像可调整大小。 如果出现问题,下面的链接可能会有用 https://www.natashatherobot.com/ios-stretchable-button-uiedgeinsetsmake/

答案 3 :(得分:2)

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")
    }

}

测试我的代码。您可以根据需要设计高度和宽度。您可以使用strokeEnd更改progressView的进度。您可以为其添加动画。但实际上,它已经是可动画的,您可以更改strokeEnd的值以查看其主要效果。如果你想设计自己的动画。请尝试CATransaction,如下所示。

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

答案 4 :(得分:1)

在init

中执行此操作
    layer.cornerRadius = *desired_corner_radius*
    clipsToBounds = true

答案 5 :(得分:1)

基本上进度视图的(默认样式)子视图由2个图像视图组成。 一种用于“进度”,另一种用于“轨道”。 您可以循环显示进度视图的子视图,并设置图像视图的每个角的半径。

for (UIView *view in self.progressView.subviews) {
    if ([view isKindOfClass:[UIImageView class]]) {
        view.clipsToBounds = YES;
        view.layer.cornerRadius = 15;
    }
}

答案 6 :(得分:1)

回答很晚了,但实际上我遇到了同样的问题。

这是我最简单的解决方案(无需代码!):

  1. 添加容器以嵌入进度视图

Container

  1. 您的容器的圆角(10 =容器的高度/ 2)

RoundCorner

  1. 结果:)

Tada!

答案 7 :(得分:1)

另一个答案,超级hacky,但使用起来很快。

您可以仅抓住子图层并设置其半径。无需编写自己的UIProgressView或将剪辑路径弄乱。

progressView.layer.cornerRadius = 5
progressView.layer.sublayers[1].cornerRadius = 5
progressView.subviews[1]. clipsToBounds = true
progressView.layer.masksToBounds = true

因此,您可以绕过整个UIProgressView(不需要ClipsToBounds) 然后,填充栏是第二个子层,因此您可以抓住它并使其角落变圆,但是还需要将该层的子视图设置为clipsToBounds。

然后将整个图层设置为遮罩其边界,一切看起来都很好。

很明显,这很大程度上依赖于UIProgressView的设置不变,而第二个子视图/图层是填充视图。

但是。如果您对此假设感到满意,请使用超级简单的代码。

答案 8 :(得分:0)

我遇到了同样的问题,这就是在疯狂谷歌搜索之后引起我的问​​题。问题是双重的。首先,如何使进度条的内部在最后进行(季亨达的答案显示该怎么做),其次,如何使你添加的CAShapeLayer的圆形末端与方形末端相匹配下面的原始进度条的答案(其他StackOverflow问题的答案有助于How to get the exact point of objects in swift?)如果你在季亨达的答案中替换了这行代码:

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

用这个:

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

您希望得到您正在寻找的结果。

答案 9 :(得分:0)

使用 swift 4.0 我正在这样做:

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

答案 10 :(得分:0)

//已更新为快速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()
 }
}

答案 11 :(得分:0)

Umair Afzal解决方案中的Swift 4.2版本

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()
}
}

并使用它

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

答案 12 :(得分:-1)

设置线上限:

.lineCap = kCALineCapRound;