如何获取 UIStackView 内的 UIView 的宽度值
How to get the width value of an UIView which is inside an UIStackView
我有自己的自定义视图,ProgressBar
,我以编程方式创建它:
let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
我使用 200 的宽度创建它,但随后我将其添加到水平堆栈视图中。因此,视图将根据屏幕尺寸增长,例如 iPhone X 将增长到 250。
在此自定义视图中,我尝试使用宽度,但它始终为 200,这会导致各种问题。
我真正需要的是视图在堆栈视图中的值,在我的例子中是 250。
有没有办法在我的自定义视图中获取该值?
或者我有什么选择?
编辑 - 添加了一些代码:
class CustomTableViewCell: UITableViewCell {
func configure() {
let progressBar: ProgressBar = {
let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
}()
}
}
并且从视图控制器调用此代码:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! CustomTableViewCell
cell.configure()
return cell
}
编辑 2 - 自定义视图代码:
class ProgressBar: UIView {
var progressView: UIView = {
let v = UIView()
v.backgroundColor = .white
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
func configure() {
backgroundColor = UIColor(white: 1.0, alpha: 0.1)
layer.cornerRadius = 8.0
clipsToBounds = true
progressView.frame = bounds
progressView.frame.size.width = 0.0
addSubview(progressView)
}
func animate(_ pct: CGFloat) -> Void {
UIView.animate(withDuration: 1.0, animations: {
self.progressView.frame.size.width = self.bounds.size.width * pct
})
}
}
edit3 - 调用动画
let progressBar: ProgressBar = {
let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
pb.translatesAutoresizingMaskIntoConstraints = false
if data.count >= i {
if let session = data[i - 1].session {
let values = Array(session).sorted(by: { [=14=].date.compare(.date) == .orderedDescending })
var sum = 0.0
for value in values {
sum += Double(value.score)
}
pb.animate(CGFloat(sum / 40)) // returns a value between 0 and 1
}
}
return pb;
}()
编辑 4:
编辑 5 - 添加调试约束:
Printing description of :
<UIView: 0x107d6a100; frame = (0 0; 200 16); layer = <CALayer: 0x1d003f3c0>>
Printing description of :
<StepUp.ProgressBar: 0x107d6c8e0; frame = (54.3333 0; 250 16); clipsToBounds = YES; layer = <CALayer: 0x1d0220880>>
正如我在评论部分提到的,将进度视图放在堆栈视图中不是一个明智的主意,这将需要繁琐的步骤来实现 width
更改动画。
首先你需要摆脱显式设置 frame
即:当你使用自动布局时不要指定宽度和高度。请改用 CGRectZero
。
然后您需要将堆栈视图(我假设您使用的是垂直堆栈视图)配置为:
stackView.alignment = .leading
您不能在此处使用任何 fill
类型。因为如果你使用填充,那么所有排列的子视图都应该具有堆栈视图的整个宽度。因此,您将无法修改它们的任何宽度以使动画发生。
现在,一旦您提供堆栈视图 .leading
对齐,您的普通视图(没有固有内容大小的视图)将被赋予 zero
的宽度。因此,当您 运行 您的应用程序时,您将看到 none 的视图。在这里你需要做一些繁琐的工作,给它们每个宽度。一种解决方案可能是:您枚举堆栈视图的子视图,并为所有视图提供与堆栈视图相同的宽度,使进度视图的宽度为零
// update these when the sub views of the view are layout already
// otherwise stack view won't have it's own size yet
stackView.subviews.forEach { (view) in
if view == progressView {
// save this constraint for use when animating
progressViewWidthConstraint = view.widthAnchor.constraint(equalToConstant: 0)
progressViewWidthConstraint.isActive = true
} else {
view.widthAnchor.constraint(equalToConstant: stackView.frame.size.width).isActive = true
}
}
现在你的动画应该是:
view.layoutIfNeeded()
progressViewWidthConstraint.constant = stackView.frame.size.width
UIView.animate(withDuration: 2) {
self.view.layoutIfNeeded()
}
结果如下:
Animate UIView as progress view inside a UIStackView
如果您在此过程中遇到困难,我已经做了 demo。干杯
我有自己的自定义视图,ProgressBar
,我以编程方式创建它:
let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
我使用 200 的宽度创建它,但随后我将其添加到水平堆栈视图中。因此,视图将根据屏幕尺寸增长,例如 iPhone X 将增长到 250。
在此自定义视图中,我尝试使用宽度,但它始终为 200,这会导致各种问题。
我真正需要的是视图在堆栈视图中的值,在我的例子中是 250。
有没有办法在我的自定义视图中获取该值?
或者我有什么选择?
编辑 - 添加了一些代码:
class CustomTableViewCell: UITableViewCell {
func configure() {
let progressBar: ProgressBar = {
let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
}()
}
}
并且从视图控制器调用此代码:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1") as! CustomTableViewCell
cell.configure()
return cell
}
编辑 2 - 自定义视图代码:
class ProgressBar: UIView {
var progressView: UIView = {
let v = UIView()
v.backgroundColor = .white
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
func configure() {
backgroundColor = UIColor(white: 1.0, alpha: 0.1)
layer.cornerRadius = 8.0
clipsToBounds = true
progressView.frame = bounds
progressView.frame.size.width = 0.0
addSubview(progressView)
}
func animate(_ pct: CGFloat) -> Void {
UIView.animate(withDuration: 1.0, animations: {
self.progressView.frame.size.width = self.bounds.size.width * pct
})
}
}
edit3 - 调用动画
let progressBar: ProgressBar = {
let pb = ProgressBar(frame: CGRect(x: 0, y: 0, width: 200, height: 16))
pb.translatesAutoresizingMaskIntoConstraints = false
if data.count >= i {
if let session = data[i - 1].session {
let values = Array(session).sorted(by: { [=14=].date.compare(.date) == .orderedDescending })
var sum = 0.0
for value in values {
sum += Double(value.score)
}
pb.animate(CGFloat(sum / 40)) // returns a value between 0 and 1
}
}
return pb;
}()
编辑 4:
编辑 5 - 添加调试约束:
Printing description of :
<UIView: 0x107d6a100; frame = (0 0; 200 16); layer = <CALayer: 0x1d003f3c0>>
Printing description of :
<StepUp.ProgressBar: 0x107d6c8e0; frame = (54.3333 0; 250 16); clipsToBounds = YES; layer = <CALayer: 0x1d0220880>>
正如我在评论部分提到的,将进度视图放在堆栈视图中不是一个明智的主意,这将需要繁琐的步骤来实现 width
更改动画。
首先你需要摆脱显式设置 frame
即:当你使用自动布局时不要指定宽度和高度。请改用 CGRectZero
。
然后您需要将堆栈视图(我假设您使用的是垂直堆栈视图)配置为:
stackView.alignment = .leading
您不能在此处使用任何 fill
类型。因为如果你使用填充,那么所有排列的子视图都应该具有堆栈视图的整个宽度。因此,您将无法修改它们的任何宽度以使动画发生。
现在,一旦您提供堆栈视图 .leading
对齐,您的普通视图(没有固有内容大小的视图)将被赋予 zero
的宽度。因此,当您 运行 您的应用程序时,您将看到 none 的视图。在这里你需要做一些繁琐的工作,给它们每个宽度。一种解决方案可能是:您枚举堆栈视图的子视图,并为所有视图提供与堆栈视图相同的宽度,使进度视图的宽度为零
// update these when the sub views of the view are layout already
// otherwise stack view won't have it's own size yet
stackView.subviews.forEach { (view) in
if view == progressView {
// save this constraint for use when animating
progressViewWidthConstraint = view.widthAnchor.constraint(equalToConstant: 0)
progressViewWidthConstraint.isActive = true
} else {
view.widthAnchor.constraint(equalToConstant: stackView.frame.size.width).isActive = true
}
}
现在你的动画应该是:
view.layoutIfNeeded()
progressViewWidthConstraint.constant = stackView.frame.size.width
UIView.animate(withDuration: 2) {
self.view.layoutIfNeeded()
}
结果如下: Animate UIView as progress view inside a UIStackView
如果您在此过程中遇到困难,我已经做了 demo。干杯