2017-06-29 79 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

相關問題