2017-06-29 59 views
1

我想创建一个横向级联的对象数组,我试图创建一个函数来减少我的代码的大小,但是,似乎可能有一个NSLayoutConstraint之间的冲突创建的对象可能是?以编程方式创建一个swift对象数组3

这里是我的代码

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的乘数或与对第一属性的位置的零秒在一起的项目将创建等于一个位置的非法拘禁不变。位置属性必须成对指定。'

有什么建议吗?

编辑

感谢抢劫的答案,我能够与调试然而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 



    } 


} 
+0

喜欢的UITableView或UIStackView的一样。 – luckyShubhra

+0

不应该'centerX'乘数乘以容器的宽度? – NRitH

+0

@NRitH乘数是一个乘数,它可以是任何数字。在那里的代码只是一个占位符atm,但它仍然应该是有效的。我只是想测试for循环。 – Stefan

回答

3
  1. 的一个问题是表达:

    CGFloat((1/2) + ((friends - 1)/50)) 
    

    这是做整数除法,然后将所得整数转换成CGFloat。在实践中,您的表达式将返回0的前50个值。

    你要你做除法之前做浮点运算,转换friends - 1CGFloat

    0.5 + CGFloat(friends - 1)/50.0 
    
  2. 我还建议你要添加的约束之前添加子视图。

  3. 您应该指定宽度和高度约束并消除frame的设置。当约束被应用时,frame将被丢弃,并且在没有宽度和高度约束的情况下,约束是不明确的。


有几个问题与你的第二个代码示例:

  • ProfileImageContainer有一个imageViewContainer,但你永远不与它做任何事情。所以,你不会看到你的ProfileImageContainers(因为你没有设置它自己的backgroundColor)。我可以想象,您最终可能会使用ProfileImageContainerimageViewContainer属性做一些有意义的事情(例如将其添加到视图层次结构中,设置图像等)。但现在,我建议你删除它,因为它只是混淆了这种情况。

  • 即使我们解决以上,子视图会重叠,因为你定义他们是一些容器的宽度的1/10,但你用1/50调整centerX乘数。

    这样做的实际效果是视图会重叠,使得看起来只有一个存在。但是我相信如果你使用视图调试器,你会发现它们都在那里。你需要改变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) 
     } 

    } 

} 
+0

这清除了调试器中的问题,但是我仍然无法创建同一对象的多个实例。请查看更新的代码。 – Stefan

+0

请参阅代码示例的修订答案。仅供参考,我也将其列在https://github.com/robertmryan/AddSubviewDemo。请参阅https://github.com/robertmryan/AddSubviewDemo/releases了解有关我对代码所做编辑的说明。 – Rob

+0

@Stefan - 坦率地说,不是自己构建这些约束条件,而是建议使用堆栈视图(请参阅https://github.com/robertmryan/AddSubviewDemo/tree/UIStackView)。它完全让您摆脱为所有子视图手动定义约束的业务。只需为堆栈视图定义约束,并让它安排其子视图。或者,如果“朋友”的数量可能会超过适合的数量,并希望能够滚动浏览它们,请使用集合视图(请参阅https://github.com/robertmryan/AddSubviewDemo/tree/UICollectionView)。 – Rob

相关问题