我需要未知元素的顶级约束

时间:2017-07-02 11:51:08

标签: ios swift constraints nslayoutconstraint

我有一个应用程序,它通过单击按钮从服务器下载图像。图像下载后,我创建一个新的imageView并将其添加到我的contentView(UIView)。我需要创建约束 - 每个新的imageview都需要前一个约束

func addNewImageToTheScrollView(img: UIImage?) {
    if let imageResponse = img {
        let imageView = UIImageView(image: imageResponse.crop(rect: CGRect(x: 0, y: imageResponse.size.height/2, width: self.contentView.frame.width, height: 200)))
        self.contentView.addSubview(imageView)

        imageView.translatesAutoresizingMaskIntoConstraints = false
        let x = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: self.contentView, attribute: .centerX, multiplier: 1.0, constant: 0)
        let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)
        let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: self.contentView, attribute: .width, multiplier: 1.0, constant: 0)
        let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 150)

        self.contentView.addConstraints([x, y])
        imageView.addConstraints([width, height])
    }
}

如果我评论约束代码,它将正常工作,除非每个新的imageView将位于视图顶部的同一位置。现在使用此约束代码,我在下载后会遇到此类代码问题

  

2017-07-02 14:50:01.018 ImageFromServerTest [11516:1080948] ***由于未捕获的异常终止应用程序' NSInvalidArgumentException',原因:' NSLayoutConstraint for>:乘数0或零第二项与第一属性的位置一起创建等于常数的位置的非法约束。必须成对指定位置属性。'

2 个答案:

答案 0 :(得分:2)

每当使用scrollViews时,都有2个拇指规则: -

  1. 为superview提供scrollView前导,尾随,底部和顶部约束,即 @IbOutlet weak var scrollView: UIScrollView! let leading = NSLayoutConstraint(item: scrollView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leadingMargin, multiplier: 1.0, constant: 0) let trailing = NSLayoutConstraint(item: scrollView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1.0, constant: 0) let top = NSLayoutConstraint(item: scrollView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1.0, constant: 0) let bottom = NSLayoutConstraint(item: scrollView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0)

    @IbOutlet weak var contentView: UIView!
    
     let leading = NSLayoutConstraint(item: contentView, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leading, multiplier: 1.0, constant: 0)
     let trailing = NSLayoutConstraint(item: contentView, attribute: .trailing, relatedBy: .equal, toItem: scrollView, attribute: .trailing, multiplier: 1.0, constant: 0)
    
     let top = NSLayoutConstraint(item: contentView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1.0, constant: 0)
    
      //increase the constant according to how much long you need the scrollview to be
     let bottom = NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1.0, constant: 0) 
    
  2. 相对于scrollView

    向contentView添加约束
    var imageViews = [UIImageViews]() //declared outside the function
    
    
        //received an image here
            var imageView = UIImageView() // define the frame according to yourself using frame init method
            imageView.image = image
    
        if imageViews.isEmpty { // first image view 
        //add constraints to first image view
    
        let x = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1.0, constant: 0)
        let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1.0, constant: 30)
        let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: self.contentView, attribute: .width, multiplier: 1.0, constant: 0)
        let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 150)
        }
    
    else { //second, third, fourth image view... so on
    
        let x = NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1.0, constant: 0)
        let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: imageViews[imageViews.count - 1], attribute: .bottom, multiplier: 1.0, constant: 30)
    
        let width = NSLayoutConstraint(item: imageView, attribute: .width, relatedBy: .equal, toItem: self.contentView, attribute: .width, multiplier: 1.0, constant: 0)
        let height = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 150)
    }
    
          imageViews.append(imageView) 
    }
    
  3. 现在添加与contentView

    相关的子视图约束(标签,图像)

    例如 - 您收到了第一张图片,因此我们将在您的函数之外维护一组UIImageViews。

    self.scrollView.contentSize  = CGSize(width, height)

    希望你现在有了一个想法,如何解决这个问题。如果有超过4或5个图像视图,您可能需要检查数组的计数并相应地增加scrollView的contentView。你可以通过使用 ArrayBlockingQueue<List<Object>> Q = new ArrayBlockingQueue<List<Object>>(); // producer side List<Object> l = new ArrayList<Object>(); for (int i=0; i<100; i++) { l.add(i); // your initialization here } Q.put(l); // consumer side List<Object> l2 = Q.take(); // do something

答案 1 :(得分:0)

我相信你有问题:

let y = NSLayoutConstraint(item: imageView, attribute: .top, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)

&#34; toItem&#34;参数应该有一些价值。第一个参数也应该是imageView.topAnchor。可能看起来应该是这样的:

let y = NSLayoutConstraint(item: imageView.topAnchor, attribute: .top, relatedBy: .equal, toItem: self.contentView.topAnchor, attribute: .notAnAttribute, multiplier: 1.0, constant: 30)