以编程方式在 ProgressView 上设置 progressTint 会更改进度条大小
Programmatically setting progressTint on ProgressView changes progress bar size
我花了好几天时间才找到这个问题的根源。
我有一个 TableView,其中包含多行自定义 Table 单元格,每个单元格中都有一个进度视图。该应用程序要求进度视图色调 green/amber/red 基于它的完整程度。
我发现以编程方式设置 progressTint 会导致进度条显示得比应有的更满。
相关代码(tableView cellForRowAt):
let Max:Double = MyGroup!.EndTimeSeconds - MyGroup!.StartTimeSeconds //10771
let Progress:Double = Date().timeIntervalSince1970 - MyGroup!.StartTimeSeconds //1599.7007069587708
if (Max >= Progress) {
Cell.DescriptionLabel.textColor = UIColor.black
Cell.SubtitleLabel.textColor = UIColor.black
Cell.TargetDeliveryTimeLabel.textColor = UIColor.pts_darkergrey
Cell.ProgressView.setProgress(Float(Progress / Max), animated: false)
Cell.ProgressView.progress = Float(Progress / Max)
Cell.ProgressView.progressTintColor = UIColor.pts_green //if i comment these out it works.
if (Max * 0.75 <= Progress) {
Cell.ProgressView.progressTintColor = UIColor.pts_pbamber //if i comment these out it works.
}
} else {
Cell.DescriptionLabel.textColor = UIColor.white
Cell.SubtitleLabel.textColor = UIColor.white
Cell.TargetDeliveryTimeLabel.textColor = UIColor.white
Cell.ProgressView.setProgress(1, animated: false)
Cell.ProgressView.progress = 1
Cell.ProgressView.progressTintColor = UIColor.pts_pbred //if i comment these out it works.
}
Cell.ProgressView.layer.cornerRadius = 4
Cell.ProgressView.clipsToBounds = true
已注释掉 progressTint 调用的屏幕截图:
progressTint 调用生效的屏幕截图:
请注意,设置色调后,第二个项目的进度条错误地填充到几乎 50%。
进度条应随时间线性填充 - 但它将保持静止,直到进度合理地超过这一点,然后它会像往常一样继续。
我可能看到了一些东西,但问题似乎一直在影响前两项,而不是其余的(影响很大,或者根本没有)
我已经尝试了 ProgressView.progress 和 ProgressView.setProgress,以及 ProgressView.progressTintColor 和 PogressView.tintColor。
经过一些搜索和测试...似乎标准 UIProgressView
不喜欢修改了高度、色调颜色 and/or 图层的某些组合。
尝试用这个 SimpleProgressView
替换你的 UIProgressView
默认值为:
- 背景颜色=白色
- tintColor = 蓝色
- 圆角半径 = 4
- 固有高度 = 4
您应该能够将其用作直接替代品——无需对现有代码进行任何其他更改。它是 @IBDesignable
,cornerRadius
和 progress
作为 @IBInspectable
,因此您可以设置它们并在 Storyboard 中查看结果。
@IBDesignable
class SimpleProgressView: UIView {
@IBInspectable public var cornerRadius: CGFloat = 0 {
didSet {
progressBarView.layer.cornerRadius = cornerRadius
layer.cornerRadius = cornerRadius
}
}
private let progressBarView = UIView()
private var widthConstraint: NSLayoutConstraint!
// default height of
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: 4.0)
}
// set the background color of the progressBarView to the tint color
override var tintColor: UIColor! {
didSet {
progressBarView.backgroundColor = tintColor
}
}
// update width constraint multiplier when progress changes
@IBInspectable public var progress: Float = 0 {
didSet {
if let wc = widthConstraint {
// cannot modify multiplier directly, so
// deactivate
wc.isActive = false
// create new width constraint with percent as multiplier
// maximum of 1.0
let pct = min(progress, 1.0)
self.widthConstraint = progressBarView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: CGFloat(pct))
// activate new width constraint
self.widthConstraint.isActive = true
}
}
}
// we can set .progress property directly, or
// call setProgress (with optional animated parameter)
public func setProgress(_ p: Float, animated: Bool) -> Void {
// don't allow animation if frame height is zero
let doAnim = animated && progressBarView.frame.height != 0
self.progress = p
if doAnim {
UIView.animate(withDuration: 0.3, animations: {
self.layoutIfNeeded()
})
}
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
if backgroundColor == nil {
backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() -> Void {
// default background color: black with 0.1 alpha
if backgroundColor == nil {
backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
// default tint color
tintColor = .blue
// default corner radius
cornerRadius = 4
progressBarView.translatesAutoresizingMaskIntoConstraints = false
addSubview(progressBarView)
// create width constraint
// progressBarView width will be set to percentage of self's width
widthConstraint = progressBarView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.0)
NSLayoutConstraint.activate([
// constrain progressBarView Top / Leading / Bottom to self
progressBarView.topAnchor.constraint(equalTo: topAnchor),
progressBarView.leadingAnchor.constraint(equalTo: leadingAnchor),
progressBarView.bottomAnchor.constraint(equalTo: bottomAnchor),
// activate width constraint
widthConstraint,
])
clipsToBounds = true
}
}
这是一个快速测试实施,比较顶部的 UIProgressView
和下面的 SimpleProgressView
。进度条将从 10% 开始,每次点击视图增加 10%,并在 25%、75% 和 100% 时改变颜色:
class ViewController: UIViewController {
let uiProgressView = UIProgressView()
let simpleProgressView = SimpleProgressView()
let labelA = UILabel()
let labelB = UILabel()
var curProgress: Float = 0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
labelA.text = "Default UIProgressView"
labelB.text = "Custom SimpleProgressView"
[labelA, uiProgressView, labelB, simpleProgressView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
labelA.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0),
labelA.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
labelA.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
uiProgressView.topAnchor.constraint(equalTo: labelA.bottomAnchor, constant: 12.0),
uiProgressView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
uiProgressView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
uiProgressView.heightAnchor.constraint(equalToConstant: 80.0),
labelB.topAnchor.constraint(equalTo: uiProgressView.bottomAnchor, constant: 40.0),
labelB.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
labelB.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
simpleProgressView.topAnchor.constraint(equalTo: labelB.bottomAnchor, constant: 12.0),
simpleProgressView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
simpleProgressView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
simpleProgressView.heightAnchor.constraint(equalToConstant: 80.0),
])
let t = UITapGestureRecognizer(target: self, action: #selector(self.incProgress(_:)))
view.addGestureRecognizer(t)
// start at 10%
incProgress(nil)
}
@objc func incProgress(_ g: UITapGestureRecognizer?) -> Void {
// increment progress by 10% on each tap, up to 100%
curProgress = min(1.0, curProgress + 0.10)
uiProgressView.progress = curProgress
simpleProgressView.progress = curProgress
let formatter = NumberFormatter()
formatter.numberStyle = .percent
formatter.maximumFractionDigits = 2
if let sPct = formatter.string(for: curProgress) {
labelA.text = "Default UIProgressView: " + sPct
labelB.text = "Custom SimpleProgressView: " + sPct
}
print(curProgress)
if curProgress == 1.0 {
uiProgressView.tintColor = .pts_red
simpleProgressView.tintColor = .pts_red
} else if curProgress >= 0.75 {
uiProgressView.tintColor = .pts_amber
simpleProgressView.tintColor = .pts_amber
} else if curProgress >= 0.25 {
uiProgressView.tintColor = .pts_green
simpleProgressView.tintColor = .pts_green
} else {
uiProgressView.tintColor = .pts_blue
simpleProgressView.tintColor = .pts_blue
}
}
}
我尝试匹配您的自定义颜色:
extension UIColor {
static let pts_green = UIColor(red: 0.35, green: 0.75, blue: 0.5, alpha: 1.0)
static let pts_amber = UIColor(red: 0.95, green: 0.7, blue: 0.0, alpha: 1.0)
static let pts_red = UIColor(red: 0.9, green: 0.35, blue: 0.35, alpha: 1.0)
static let pts_blue = UIColor(red: 0.25, green: 0.75, blue: 1.0, alpha: 1.0)
static let pts_darkergrey = UIColor(white: 0.2, alpha: 1.0)
}
我花了好几天时间才找到这个问题的根源。
我有一个 TableView,其中包含多行自定义 Table 单元格,每个单元格中都有一个进度视图。该应用程序要求进度视图色调 green/amber/red 基于它的完整程度。
我发现以编程方式设置 progressTint 会导致进度条显示得比应有的更满。
相关代码(tableView cellForRowAt):
let Max:Double = MyGroup!.EndTimeSeconds - MyGroup!.StartTimeSeconds //10771
let Progress:Double = Date().timeIntervalSince1970 - MyGroup!.StartTimeSeconds //1599.7007069587708
if (Max >= Progress) {
Cell.DescriptionLabel.textColor = UIColor.black
Cell.SubtitleLabel.textColor = UIColor.black
Cell.TargetDeliveryTimeLabel.textColor = UIColor.pts_darkergrey
Cell.ProgressView.setProgress(Float(Progress / Max), animated: false)
Cell.ProgressView.progress = Float(Progress / Max)
Cell.ProgressView.progressTintColor = UIColor.pts_green //if i comment these out it works.
if (Max * 0.75 <= Progress) {
Cell.ProgressView.progressTintColor = UIColor.pts_pbamber //if i comment these out it works.
}
} else {
Cell.DescriptionLabel.textColor = UIColor.white
Cell.SubtitleLabel.textColor = UIColor.white
Cell.TargetDeliveryTimeLabel.textColor = UIColor.white
Cell.ProgressView.setProgress(1, animated: false)
Cell.ProgressView.progress = 1
Cell.ProgressView.progressTintColor = UIColor.pts_pbred //if i comment these out it works.
}
Cell.ProgressView.layer.cornerRadius = 4
Cell.ProgressView.clipsToBounds = true
已注释掉 progressTint 调用的屏幕截图:
progressTint 调用生效的屏幕截图:
请注意,设置色调后,第二个项目的进度条错误地填充到几乎 50%。
进度条应随时间线性填充 - 但它将保持静止,直到进度合理地超过这一点,然后它会像往常一样继续。
我可能看到了一些东西,但问题似乎一直在影响前两项,而不是其余的(影响很大,或者根本没有)
我已经尝试了 ProgressView.progress 和 ProgressView.setProgress,以及 ProgressView.progressTintColor 和 PogressView.tintColor。
经过一些搜索和测试...似乎标准 UIProgressView
不喜欢修改了高度、色调颜色 and/or 图层的某些组合。
尝试用这个 SimpleProgressView
UIProgressView
默认值为:
- 背景颜色=白色
- tintColor = 蓝色
- 圆角半径 = 4
- 固有高度 = 4
您应该能够将其用作直接替代品——无需对现有代码进行任何其他更改。它是 @IBDesignable
,cornerRadius
和 progress
作为 @IBInspectable
,因此您可以设置它们并在 Storyboard 中查看结果。
@IBDesignable
class SimpleProgressView: UIView {
@IBInspectable public var cornerRadius: CGFloat = 0 {
didSet {
progressBarView.layer.cornerRadius = cornerRadius
layer.cornerRadius = cornerRadius
}
}
private let progressBarView = UIView()
private var widthConstraint: NSLayoutConstraint!
// default height of
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: 4.0)
}
// set the background color of the progressBarView to the tint color
override var tintColor: UIColor! {
didSet {
progressBarView.backgroundColor = tintColor
}
}
// update width constraint multiplier when progress changes
@IBInspectable public var progress: Float = 0 {
didSet {
if let wc = widthConstraint {
// cannot modify multiplier directly, so
// deactivate
wc.isActive = false
// create new width constraint with percent as multiplier
// maximum of 1.0
let pct = min(progress, 1.0)
self.widthConstraint = progressBarView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: CGFloat(pct))
// activate new width constraint
self.widthConstraint.isActive = true
}
}
}
// we can set .progress property directly, or
// call setProgress (with optional animated parameter)
public func setProgress(_ p: Float, animated: Bool) -> Void {
// don't allow animation if frame height is zero
let doAnim = animated && progressBarView.frame.height != 0
self.progress = p
if doAnim {
UIView.animate(withDuration: 0.3, animations: {
self.layoutIfNeeded()
})
}
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
if backgroundColor == nil {
backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() -> Void {
// default background color: black with 0.1 alpha
if backgroundColor == nil {
backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
// default tint color
tintColor = .blue
// default corner radius
cornerRadius = 4
progressBarView.translatesAutoresizingMaskIntoConstraints = false
addSubview(progressBarView)
// create width constraint
// progressBarView width will be set to percentage of self's width
widthConstraint = progressBarView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.0)
NSLayoutConstraint.activate([
// constrain progressBarView Top / Leading / Bottom to self
progressBarView.topAnchor.constraint(equalTo: topAnchor),
progressBarView.leadingAnchor.constraint(equalTo: leadingAnchor),
progressBarView.bottomAnchor.constraint(equalTo: bottomAnchor),
// activate width constraint
widthConstraint,
])
clipsToBounds = true
}
}
这是一个快速测试实施,比较顶部的 UIProgressView
和下面的 SimpleProgressView
。进度条将从 10% 开始,每次点击视图增加 10%,并在 25%、75% 和 100% 时改变颜色:
class ViewController: UIViewController {
let uiProgressView = UIProgressView()
let simpleProgressView = SimpleProgressView()
let labelA = UILabel()
let labelB = UILabel()
var curProgress: Float = 0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
labelA.text = "Default UIProgressView"
labelB.text = "Custom SimpleProgressView"
[labelA, uiProgressView, labelB, simpleProgressView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
}
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
labelA.topAnchor.constraint(equalTo: g.topAnchor, constant: 100.0),
labelA.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
labelA.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
uiProgressView.topAnchor.constraint(equalTo: labelA.bottomAnchor, constant: 12.0),
uiProgressView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
uiProgressView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
uiProgressView.heightAnchor.constraint(equalToConstant: 80.0),
labelB.topAnchor.constraint(equalTo: uiProgressView.bottomAnchor, constant: 40.0),
labelB.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
labelB.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
simpleProgressView.topAnchor.constraint(equalTo: labelB.bottomAnchor, constant: 12.0),
simpleProgressView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
simpleProgressView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
simpleProgressView.heightAnchor.constraint(equalToConstant: 80.0),
])
let t = UITapGestureRecognizer(target: self, action: #selector(self.incProgress(_:)))
view.addGestureRecognizer(t)
// start at 10%
incProgress(nil)
}
@objc func incProgress(_ g: UITapGestureRecognizer?) -> Void {
// increment progress by 10% on each tap, up to 100%
curProgress = min(1.0, curProgress + 0.10)
uiProgressView.progress = curProgress
simpleProgressView.progress = curProgress
let formatter = NumberFormatter()
formatter.numberStyle = .percent
formatter.maximumFractionDigits = 2
if let sPct = formatter.string(for: curProgress) {
labelA.text = "Default UIProgressView: " + sPct
labelB.text = "Custom SimpleProgressView: " + sPct
}
print(curProgress)
if curProgress == 1.0 {
uiProgressView.tintColor = .pts_red
simpleProgressView.tintColor = .pts_red
} else if curProgress >= 0.75 {
uiProgressView.tintColor = .pts_amber
simpleProgressView.tintColor = .pts_amber
} else if curProgress >= 0.25 {
uiProgressView.tintColor = .pts_green
simpleProgressView.tintColor = .pts_green
} else {
uiProgressView.tintColor = .pts_blue
simpleProgressView.tintColor = .pts_blue
}
}
}
我尝试匹配您的自定义颜色:
extension UIColor {
static let pts_green = UIColor(red: 0.35, green: 0.75, blue: 0.5, alpha: 1.0)
static let pts_amber = UIColor(red: 0.95, green: 0.7, blue: 0.0, alpha: 1.0)
static let pts_red = UIColor(red: 0.9, green: 0.35, blue: 0.35, alpha: 1.0)
static let pts_blue = UIColor(red: 0.25, green: 0.75, blue: 1.0, alpha: 1.0)
static let pts_darkergrey = UIColor(white: 0.2, alpha: 1.0)
}