iOS9 ScrollView里面的StackView没有填满屏幕的宽度
iOS 9 StackView inside ScrollView does not fill the width of the screen
我正在尝试制作一个 UIScrollView
,其中包含一个 UIStackView
,其中嵌套了多层堆栈视图。我想使用 AutoLayout,但是我正在做的事情有问题,而且我的大脑越来越混乱,试图弄清楚:
import UIKit
class HomeView: UIView {
let looks = sampleLooks
let user = sampleUser
let streamView: UIStackView = UIStackView(arrangedSubviews: [])
let scrollView: UIScrollView = UIScrollView()
func makeButtonWithTitle(title: String, image: UIImage?, selector: String, tag: Int) -> UIButton {
let button = UIButton(type: .System)
button.setImage(image, forState: .Normal)
button.tintColor = UIColor.blackColor()
switch tag {
case 0...10:
button.backgroundColor = UIColor(white: 0.98, alpha: 0.8)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Thin", size: 30)
default:
button.backgroundColor = UIColor(white: 0.90, alpha: 1.0)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Thin", size: 40)
}
button.setTitle(title, forState: .Normal)
button.tag = tag
return button
}
func makeMessageView(senderImage: UIImage, senderHandle: String, text: String) -> UIView {
let textView = UILabel()
textView.text = text
textView.font = UIFont(name: "HelveticaNeue-Thin", size: 20)
let senderLabel = UILabel()
senderLabel.text = senderHandle
textView.font = UIFont(name: "HelveticaNeue-Thin", size: 20)
let textStackView = UIStackView(arrangedSubviews:[senderLabel, textView])
textStackView.axis = .Horizontal
textStackView.alignment = .Fill
textStackView.distribution = .Fill
let postView = UIView()
postView.addSubview(textStackView)
postView.backgroundColor = UIColor(white: 0.98, alpha: 0.8)
return postView
}
required init?(coder:NSCoder) {
super.init(coder:coder)
self.contentMode = .ScaleToFill
self.backgroundColor = UIColor(patternImage: UIImage(named: "background")!)
self.streamView.spacing = 20.0
self.streamView.translatesAutoresizingMaskIntoConstraints = false
self.streamView.axis = .Vertical
self.streamView.alignment = .Fill
self.streamView.distribution = .FillEqually
for look in self.looks {
let lookImageView = UIImageView(image: look.photo.photo)
lookImageView.contentMode = .ScaleAspectFit
lookImageView.clipsToBounds = true
let postView = self.makeMessageView(
look.user.photo.photo, senderHandle: look.user.handle, text: look.post)
let likeButton = self.makeButtonWithTitle(
" Like", image: UIImage(named: "like"), selector: "", tag: 0)
let commentButton = self.makeButtonWithTitle(
" Comment", image: UIImage(named: "SMS"), selector: "", tag: 1)
let shareButton = self.makeButtonWithTitle(
" Share", image: UIImage(named: "upload"), selector: "", tag: 2)
let buttonsView = UIStackView(arrangedSubviews: [likeButton, commentButton, shareButton])
buttonsView.distribution = .FillEqually
let lookView = UIStackView(arrangedSubviews:[lookImageView, postView, buttonsView])
lookView.axis = .Vertical
lookView.distribution = .Fill
lookView.alignment = .Fill
self.streamView.addArrangedSubview(lookView)
}
self.scrollView.addSubview(self.streamView)
self.scrollView.frame = UIScreen.mainScreen().bounds
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false
self.addSubview(self.scrollView)
}
}
所以,我希望这段代码做的是给我一个可滚动的嵌套堆栈,覆盖屏幕的宽度(如果图像被剪裁没关系,但我希望它们覆盖画面无失真)。它实际上给我的是一组可滚动的图像,其中第一张图像的宽度(表面上)决定了堆栈的宽度。我实际上不确定这是不是发生了什么,但是顶层 UIStackView
没有覆盖屏幕的宽度。
我认为这与UIScrollView
没有固有宽度有关,所以它里面的堆栈视图决定了它自己的大小。我这样说是因为如果我将堆栈视图直接放在父视图中,它会覆盖显示,但是正如您所料,没有滚动...
您需要在滚动视图和它包含的 UIStackView 之间设置一些约束,目前您没有。
这三个足以使内部 UIStackView 与滚动视图大小相同:
- 滚动视图和 UIStackView 之间的水平约束,它们之间没有 space
- 滚动视图和 UIStackView 之间的垂直约束,它们之间没有 space,这样您就可以滚动到 UIStackView 的整个高度
- 滚动视图和 UIStackView 的宽度相同,这样 UIStackView 将匹配滚动视图的宽度
这是代码:
//You already have these two lines:
//scrollView.addSubview(streamView)
//streamView.translatesAutoresizingMaskIntoConstraints = false;
//Add this one too:
scrollView.translatesAutoresizingMaskIntoConstraints = false;
scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("V:|[innerView]|",
options: NSLayoutFormatOptions(rawValue:0),
metrics: nil,
views: ["innerView":streamView]))
scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("H:|[innerView]|",
options: NSLayoutFormatOptions(rawValue:0),
metrics: nil,
views: ["innerView":streamView]))
scrollView.addConstraint(
NSLayoutConstraint(item: scrollView,
attribute: .Width,
relatedBy: .Equal,
toItem: streamView,
attribute: .Width,
multiplier: 1.0,
constant: 0))
或者,您可以使用将视图嵌入滚动视图的方法来扩展 UIView:
extension UIView {
func embedInScrollView()->UIView{
let cont=UIScrollView()
self.translatesAutoresizingMaskIntoConstraints = false;
cont.translatesAutoresizingMaskIntoConstraints = false;
cont.addSubview(self)
cont.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[innerView]|", options: NSLayoutFormatOptions(rawValue:0),metrics: nil, views: ["innerView":self]))
cont.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[innerView]|", options: NSLayoutFormatOptions(rawValue:0),metrics: nil, views: ["innerView":self]))
cont.addConstraint(NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: cont, attribute: .Width, multiplier: 1.0, constant: 0))
return cont
}
}
并这样使用:
let scrollView = streamView.embedInScrollView()
编辑:修复了第一个片段中的最后一个约束。
我正在尝试制作一个 UIScrollView
,其中包含一个 UIStackView
,其中嵌套了多层堆栈视图。我想使用 AutoLayout,但是我正在做的事情有问题,而且我的大脑越来越混乱,试图弄清楚:
import UIKit
class HomeView: UIView {
let looks = sampleLooks
let user = sampleUser
let streamView: UIStackView = UIStackView(arrangedSubviews: [])
let scrollView: UIScrollView = UIScrollView()
func makeButtonWithTitle(title: String, image: UIImage?, selector: String, tag: Int) -> UIButton {
let button = UIButton(type: .System)
button.setImage(image, forState: .Normal)
button.tintColor = UIColor.blackColor()
switch tag {
case 0...10:
button.backgroundColor = UIColor(white: 0.98, alpha: 0.8)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Thin", size: 30)
default:
button.backgroundColor = UIColor(white: 0.90, alpha: 1.0)
button.titleLabel?.font = UIFont(name: "HelveticaNeue-Thin", size: 40)
}
button.setTitle(title, forState: .Normal)
button.tag = tag
return button
}
func makeMessageView(senderImage: UIImage, senderHandle: String, text: String) -> UIView {
let textView = UILabel()
textView.text = text
textView.font = UIFont(name: "HelveticaNeue-Thin", size: 20)
let senderLabel = UILabel()
senderLabel.text = senderHandle
textView.font = UIFont(name: "HelveticaNeue-Thin", size: 20)
let textStackView = UIStackView(arrangedSubviews:[senderLabel, textView])
textStackView.axis = .Horizontal
textStackView.alignment = .Fill
textStackView.distribution = .Fill
let postView = UIView()
postView.addSubview(textStackView)
postView.backgroundColor = UIColor(white: 0.98, alpha: 0.8)
return postView
}
required init?(coder:NSCoder) {
super.init(coder:coder)
self.contentMode = .ScaleToFill
self.backgroundColor = UIColor(patternImage: UIImage(named: "background")!)
self.streamView.spacing = 20.0
self.streamView.translatesAutoresizingMaskIntoConstraints = false
self.streamView.axis = .Vertical
self.streamView.alignment = .Fill
self.streamView.distribution = .FillEqually
for look in self.looks {
let lookImageView = UIImageView(image: look.photo.photo)
lookImageView.contentMode = .ScaleAspectFit
lookImageView.clipsToBounds = true
let postView = self.makeMessageView(
look.user.photo.photo, senderHandle: look.user.handle, text: look.post)
let likeButton = self.makeButtonWithTitle(
" Like", image: UIImage(named: "like"), selector: "", tag: 0)
let commentButton = self.makeButtonWithTitle(
" Comment", image: UIImage(named: "SMS"), selector: "", tag: 1)
let shareButton = self.makeButtonWithTitle(
" Share", image: UIImage(named: "upload"), selector: "", tag: 2)
let buttonsView = UIStackView(arrangedSubviews: [likeButton, commentButton, shareButton])
buttonsView.distribution = .FillEqually
let lookView = UIStackView(arrangedSubviews:[lookImageView, postView, buttonsView])
lookView.axis = .Vertical
lookView.distribution = .Fill
lookView.alignment = .Fill
self.streamView.addArrangedSubview(lookView)
}
self.scrollView.addSubview(self.streamView)
self.scrollView.frame = UIScreen.mainScreen().bounds
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false
self.addSubview(self.scrollView)
}
}
所以,我希望这段代码做的是给我一个可滚动的嵌套堆栈,覆盖屏幕的宽度(如果图像被剪裁没关系,但我希望它们覆盖画面无失真)。它实际上给我的是一组可滚动的图像,其中第一张图像的宽度(表面上)决定了堆栈的宽度。我实际上不确定这是不是发生了什么,但是顶层 UIStackView
没有覆盖屏幕的宽度。
我认为这与UIScrollView
没有固有宽度有关,所以它里面的堆栈视图决定了它自己的大小。我这样说是因为如果我将堆栈视图直接放在父视图中,它会覆盖显示,但是正如您所料,没有滚动...
您需要在滚动视图和它包含的 UIStackView 之间设置一些约束,目前您没有。
这三个足以使内部 UIStackView 与滚动视图大小相同:
- 滚动视图和 UIStackView 之间的水平约束,它们之间没有 space
- 滚动视图和 UIStackView 之间的垂直约束,它们之间没有 space,这样您就可以滚动到 UIStackView 的整个高度
- 滚动视图和 UIStackView 的宽度相同,这样 UIStackView 将匹配滚动视图的宽度
这是代码:
//You already have these two lines:
//scrollView.addSubview(streamView)
//streamView.translatesAutoresizingMaskIntoConstraints = false;
//Add this one too:
scrollView.translatesAutoresizingMaskIntoConstraints = false;
scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("V:|[innerView]|",
options: NSLayoutFormatOptions(rawValue:0),
metrics: nil,
views: ["innerView":streamView]))
scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("H:|[innerView]|",
options: NSLayoutFormatOptions(rawValue:0),
metrics: nil,
views: ["innerView":streamView]))
scrollView.addConstraint(
NSLayoutConstraint(item: scrollView,
attribute: .Width,
relatedBy: .Equal,
toItem: streamView,
attribute: .Width,
multiplier: 1.0,
constant: 0))
或者,您可以使用将视图嵌入滚动视图的方法来扩展 UIView:
extension UIView {
func embedInScrollView()->UIView{
let cont=UIScrollView()
self.translatesAutoresizingMaskIntoConstraints = false;
cont.translatesAutoresizingMaskIntoConstraints = false;
cont.addSubview(self)
cont.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[innerView]|", options: NSLayoutFormatOptions(rawValue:0),metrics: nil, views: ["innerView":self]))
cont.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[innerView]|", options: NSLayoutFormatOptions(rawValue:0),metrics: nil, views: ["innerView":self]))
cont.addConstraint(NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: cont, attribute: .Width, multiplier: 1.0, constant: 0))
return cont
}
}
并这样使用:
let scrollView = streamView.embedInScrollView()
编辑:修复了第一个片段中的最后一个约束。