如何以编程方式使用自动布局在滚动视图中水平放置N个视图?

我想在scrollview中水平创建N个视图。 所以我创建了一个临时视图,并为此分配了当前视图 。然后我根据该视图放置了约束。只有一个视图显示其他人没有显示。 我想要两个视图之间的水平空间。 我正在使用VFL设置自动布局。 这是我尝试的代码。

func ect() { let scrollHeight = self.scrollObj.frame.size.height - 40 let scrollHeightString = String(describing: scrollHeight) print(scrollHeightString) var firstTextView = UIView() // this is temporary view var columnIndex: CGFloat = 0 for _ in 0 ..< 5 { let textViewSample = UITextView() textViewSample.translatesAutoresizingMaskIntoConstraints = false //textViewSample.attributedText = self.htmlString.utf8Data?.attributedString textViewSample.isScrollEnabled = false textViewSample.tag = Int(columnIndex) textViewSample.backgroundColor = UIColor.green self.scrollObj.addSubview(textViewSample) if columnIndex == 0{ //here i am setting first view to left margin. self.scrollObj.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[textViewSample]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["textViewSample":textViewSample])) //height to textview self.scrollObj.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[textViewSample(200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["textViewSample":textViewSample])) //width to textview self.scrollObj.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[textViewSample(200)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["textViewSample":textViewSample])) }else{ //setting horizontal space to Temp view and current view self.scrollObj.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[firstTextView]-(10)-[textViewSample]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["textViewSample":textViewSample,"firstTextView":firstTextView])) //setting equal width and equal height to second textview based on first self.scrollObj.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[firstTextView][textViewSample(==firstTextView)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["textViewSample":textViewSample,"firstTextView":firstTextView])) } //y position to textview self.scrollObj.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(20)-[textViewSample]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["textViewSample":textViewSample])) firstTextView = textViewSample//assigning current view to temp view. // Increase the current offset columnIndex = columnIndex + 1 } self.scrollObj.contentSize = CGSize(width: columnIndex*200, height: columnIndex*200) self.scrollObj .setNeedsLayout() self.scrollObj.layoutIfNeeded() } 

这就是我的设计: –

在此处输入图像描述

在此处输入图像描述

如果你想使用约束,你可以这样做:

 var previousAnchor = scrollView.leadingAnchor for _ in 0 ..< 5 { let textView = UITextView() textView.translatesAutoresizingMaskIntoConstraints = false textView.backgroundColor = .green textView.isScrollEnabled = false scrollView.addSubview(textView) NSLayoutConstraint.activate([ textView.leadingAnchor.constraint(equalTo: previousAnchor, constant: 10), textView.heightAnchor.constraint(equalToConstant: 200), textView.widthAnchor.constraint(equalToConstant: 200), textView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 10), textView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -10) ]) previousAnchor = textView.trailingAnchor } previousAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -10).isActive = true 

从概念上讲,它与您拥有的相似:因此,对于每个文本视图,将宽度设置为200,将高度设置为200,将前一个视图的空间设置为10.对于第一个视图,它从滚动视图的前沿开始为10,对于最后一个视图,从滚动视图的后缘开始是10。

无需调整内容大小。 没有布局相关的电话。 只需添加约束即可。


在注释中,您说您希望文本视图的宽度为滚动视图边界的三分之一。 由于滚动视图的约束的微妙性(参见TN2154 ,滚动视图及其子视图之间的约束实际上在滚动视图的contentSize和子视图之间,而不是滚动视图的frame之间),您不能说⅓滚动视图。 但是您可以说滚动视图所在的视图,例如将上面的200pt宽度约束替换为:

 textView.widthAnchor.constraint(equalTo: scrollViewContainer.widthAnchor, multiplier: 1.0 / 3.0, constant: -13), 

同样地,你说你希望它是滚动视图的高度限制小于10(可能在两侧)。 所以你可以做一些事情,再次用以下方法替换200pt固定高度约束:

 textView.heightAnchor.constraint(equalTo: scrollViewContainer.heightAnchor, constant: -20) 

现在,因为你不能引用scrollview的bounds ,我所做的是将滚动视图放在容器视图( scrollViewContainer )中,因此这个父视图的边界与滚动视图的边界相同。 现在,约束可以引用此父视图,您将相对于滚动视图的边界而不是滚动视图的contentSize设置这些子视图。

但是当你这样做时,你会看到滚动视图中的前三个视图(我可以向右滚动以查看其余视图):

在此处输入图像描述

在我的演示中,我做到了这一点,

ViewDidLoad

  // add scrollView let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)) self.view.addSubview(scrollView) // scrollview contraints scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true scrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0).isActive = true scrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0).isActive = true // add viewContainer let viewContainer = UIView(frame: CGRect(x: 0, y: 0, width: scrollView.frame.size.width, height: scrollView.frame.size.height)) // View just after the SV viewContainer.backgroundColor = UIColor.lightGray scrollView.addSubview(viewContainer) // viewcontainer contraints //viewContainer.translatesAutoresizingMaskIntoConstraints = false viewContainer.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0).isActive = true viewContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true viewContainer.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true viewContainer.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0).isActive = true // add different subview in scrollview var originY:Int = 0 for i in 0 ..< 5 { let myInnerView = UIView(frame: CGRect(x: 0, y: originY , width: Int(scrollView.frame.size.width), height: 100)) myInnerView.translatesAutoresizingMaskIntoConstraints = false viewContainer.addSubview(myInnerView) // for different UI different color switch i { case 0: myInnerView.backgroundColor = UIColor.green break case 1: myInnerView.backgroundColor = UIColor.purple break case 2: myInnerView.backgroundColor = UIColor.yellow break case 3: myInnerView.backgroundColor = UIColor.orange break case 4: myInnerView.backgroundColor = UIColor.blue break default: break } originY = originY+100+20 } 

添加此方法

 override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) { self.view.layoutIfNeeded() } 

输出:

在此处输入图像描述

在此处输入图像描述