以编程方式快速创建对象数组 3
Posted
技术标签:
【中文标题】以编程方式快速创建对象数组 3【英文标题】:Programmatically create an array of objects swift 3 【发布时间】:2017-06-29 04:15:06 【问题描述】:我想创建一个水平级联的对象数组,我试图创建一个函数来减小我的代码大小,但是,创建的对象之间似乎可能存在 NSLayoutConstraint 冲突?
这是我的代码
private func createProfileImageContainers(numberOfFriends: Int)
for friends in 1...numberOfFriends
let imageViewContainer = UIView()
imageViewContainer.translatesAutoresizingMaskIntoConstraints = false
imageViewContainer.backgroundColor = UIColor.blue
imageViewContainer.frame = CGRect(x: 0, y: 0, width: frame.width / 10, height: frame.width / 10)
NSLayoutConstraint(item: imageViewContainer, attribute: .centerX, relatedBy: .equal, toItem: container, attribute: .centerX, multiplier: CGFloat((1 / 2) + ((friends - 1) / 50 )), constant: 0).isActive = true
NSLayoutConstraint(item: imageViewContainer, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
addSubview(imageViewContainer)
这是调试器的意思
乘数 0 或 nil 第二项与第一个属性的位置一起创建了位置等于常数的非法约束。位置属性必须成对指定。'
有什么建议吗?
编辑:
感谢 Robs 的回答,我能够解决调试器的问题,但是只添加了一个 imageViewContainer 实例。可能是因为它们都被添加到具有相同名称的视图层次结构中,所以每个新视图都会取代最后一个...... 我认为创建一个类可以解决这个问题,但现在我什么都没有出现。
这是更新后的代码...
class profileImageContainer: UIView
let imageViewContainer: UIView =
let iv = UIView()
iv.translatesAutoresizingMaskIntoConstraints = false
iv.backgroundColor = UIColor.blue
return iv
()
private func createProfileImageContainers(numberOfFriends: Int)
for friends in 1...numberOfFriends
print(friends)
let imageViewContainer = profileImageContainer()
addSubview(imageViewContainer)
NSLayoutConstraint(item: imageViewContainer, attribute: .width, relatedBy: .equal, toItem: container, attribute: .width, multiplier: 0.1, constant: 0).isActive = true
NSLayoutConstraint(item: imageViewContainer, attribute: .height, relatedBy: .equal, toItem: container, attribute: .width, multiplier: 0.1, constant: 0).isActive = true
NSLayoutConstraint(item: imageViewContainer, attribute: .centerX, relatedBy: .equal, toItem: container, attribute: .centerX, multiplier: 0.5 + (CGFloat(friends - 1) / 50.0), constant: 0).isActive = true
NSLayoutConstraint(item: imageViewContainer, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0).isActive = true
【问题讨论】:
更喜欢 UITableView 或 UIStackView 。 不应该centerX
乘数乘以容器的宽度吗?
@NRitH 乘数是一个乘数,它可以是任何数字。那里的代码只是一个占位符 atm,但它仍然应该是有效的。我只是想测试 for in 循环。
对于 luckyShubhra 的观点,如果您想考虑重构它,堆栈视图(如果您不需要滚动能力)可以让您摆脱为所有子视图定义约束。您只需要堆栈视图的约束,将其指定为水平堆栈视图并告诉它均匀排列其排列的视图。然后它将负责安排所有子视图。或者,如果您想要水平滚动功能,您可以使用集合视图。但我知道,如果你想让这个工作,首先。
@luckyShubhra 我要做的就是创建8个圆圈,每个圆圈的左边缘都是前一个圆圈centerx。我可以一个一个地创建每个视图,但这似乎不是最优的。
【参考方案1】:
一个问题是表达式:
CGFloat((1 / 2) + ((friends - 1) / 50))
这是进行整数除法,然后将得到的整数转换为CGFloat
。实际上,您的表达式将为前 50 个 friends
值返回 0
。
您想进行浮点数学运算,在进行除法之前将friends - 1
转换为CGFloat
:
0.5 + CGFloat(friends - 1) / 50.0
我还建议您在添加约束之前添加子视图。
您应该指定宽度和高度约束并取消frame
的设置。 frame
将在应用约束时被丢弃,并且在没有宽度和高度约束的情况下,约束是不明确的。
您的第二个代码示例存在几个问题:
您的ProfileImageContainer
有一个imageViewContainer
,但您从不使用它。所以,你不会看到你的ProfileImageContainers
(因为你没有设置自己的backgroundColor
)。我可以想象你最终可能会用ProfileImageContainer
的imageViewContainer
属性做一些有意义的事情(例如,将它添加到视图层次结构中,设置图像等)。但是现在,我建议你删除它,因为它只会让情况变得混乱。
即使我们修复了上述问题,子视图也会重叠,因为您已将它们定义为某个容器宽度的 1/10,但您将 centerX
乘数调整了 1/50。
这样做的最终结果是视图将重叠,看起来只有一个存在。但我相信如果你使用视图调试器,你会发现它们都在那里。您需要更改 centerX 约束,使它们不会重叠。
无论如何,这里有一个解决上述问题的版本:
// SampleView.swift
import UIKit
class ProfileImageContainer: UIView
override init(frame: CGRect)
super.init(frame: frame)
configure()
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
configure()
func configure()
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .blue
class SampleView: UIView
var container: UIView!
override init(frame: CGRect = .zero)
super.init(frame: frame)
configure()
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
configure()
func configure()
container = UIView()
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
NSLayoutConstraint.activate([
container.leftAnchor.constraint(equalTo: leftAnchor),
container.rightAnchor.constraint(equalTo: rightAnchor),
container.topAnchor.constraint(equalTo: topAnchor),
container.bottomAnchor.constraint(equalTo: bottomAnchor)
])
createProfileImageContainers(numberOfFriends: 5)
var friends = [UIView]()
private func createProfileImageContainers(numberOfFriends: Int)
// remove old friends in case you called this before
friends.forEach $0.removeFromSuperview()
friends.removeAll()
// now add friends
for friend in 0 ..< numberOfFriends // easier to go from 0 to numberOfFriends-1 than subtract one later
print(friend)
let imageViewContainer = ProfileImageContainer()
container.addSubview(imageViewContainer)
NSLayoutConstraint.activate([
imageViewContainer.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.1),
imageViewContainer.heightAnchor.constraint(equalTo: container.heightAnchor, multiplier: 0.1),
NSLayoutConstraint(item: imageViewContainer, attribute: .centerX, relatedBy: .equal, toItem: container, attribute: .centerX, multiplier: 2 * CGFloat(friend + 1) / CGFloat(numberOfFriends + 1), constant: 0),
imageViewContainer.centerYAnchor.constraint(equalTo: container.centerYAnchor)
])
friends.append(imageViewContainer)
【讨论】:
这清除了调试器中的问题,但是我仍然无法创建同一对象的多个实例。请查看更新后的代码。 查看带有代码示例的修订答案。仅供参考,我也在github.com/robertmryan/AddSubviewDemo 发布。请参阅 github.com/robertmryan/AddSubviewDemo/releases 了解我对您的代码所做的编辑。 @Stefan - 坦率地说,与其自己构建这些约束,我建议使用堆栈视图(参见github.com/robertmryan/AddSubviewDemo/tree/UIStackView)。它完全让您摆脱为所有子视图手动定义约束的工作。只需为堆栈视图定义约束,并让它排列其子视图。或者,如果“朋友”的数量可能超过了可以容纳的数量,并且您希望能够滚动浏览它们,请使用集合视图(请参阅github.com/robertmryan/AddSubviewDemo/tree/UICollectionView)。以上是关于以编程方式快速创建对象数组 3的主要内容,如果未能解决你的问题,请参考以下文章