问题
I want to create N number of views in horizontally in scrollview. so I have created One Temporary View and i assigned current view to that.Then i place constraints based on that.Only one view showing others not showing. I want Horizontal space between two views. I am using VFL to set a auto layout. Here is my trying code.
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()
}
This is what my design:-
回答1:
If you want to use constraints, you could do something like this:
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
Conceptually it's similar to what you have: So, for every text view, set the width to 200, height to 200, space to the prior view to 10. For the first view, it's 10 from the leading edge of the scroll view and for the last view, it's 10 from the trailing edge of the scroll view.
No content size adjustment is needed. No layout related calls. Just add the constraints and you're done.
In comments, you say you want the width of the text view to be one third of the scroll view's bounds. Because of the subtleties of constraints with scroll views (see TN2154, where constraints between a scroll view and its subviews are really between the contentSize
of the scroll view and the subview, not the frame
of the scroll view), you can't say ⅓ of the scroll view. But you can say ⅓ of the view the scroll view is in, e.g. replace the 200pt width constraint above with:
textView.widthAnchor.constraint(equalTo: scrollViewContainer.widthAnchor, multiplier: 1.0 / 3.0, constant: -13),
Likewise, you said you wanted it to be the height of the scroll view bounds less 10 (presumably on both sides). So you could do something like, again replacing the 200pt fixed height constraint with:
textView.heightAnchor.constraint(equalTo: scrollViewContainer.heightAnchor, constant: -20)
Now, because you cannot refer to the bounds
of the scrollview, what I did was I put the scroll view inside a container view (scrollViewContainer
), so the bounds of this parent view are the same as that of the scroll view. Now the constraints can refer to this parent view and you'll set these subviews relative to the bounds of the scroll view rather than the contentSize
of the scroll view.
But when you do that, you see the first three views within the scroll view (and I can scroll to the right to see the rest):
回答2:
In my demo I have done this,
In 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
}
Add this method
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
self.view.layoutIfNeeded()
}
Output:
来源:https://stackoverflow.com/questions/41477626/how-to-place-n-number-of-views-horizontally-in-scrollview-using-auto-layout-prog