【问题标题】:iOS 9 StackView inside ScrollView does not fill the width of the screenScrollView中的iOS 9 StackView不会填满屏幕的宽度
【发布时间】:2016-02-10 08:20:37
【问题描述】:

我正在尝试制作一个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 没有内在宽度有关,因此它内部的堆栈视图决定了它自己的大小。我这样说是因为如果我将堆栈视图直接放在父视图中,它会覆盖显示,但正如您所料,没有滚动...

【问题讨论】:

    标签: ios swift ipad autolayout ios9


    【解决方案1】:

    您需要在滚动视图和它包含的 UIStackView 之间设置一些约束,目前您没有任何约束。

    这三个足以让内部的UIStackView和scrollview一样大小:

    • 滚动视图和 UIStackView 之间的水平约束,它们之间没有空格
    • scrollview 和 UIStackView 之间的垂直约束,它们之间没有空间,这样你就可以滚动到 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()
    

    编辑:修复了第一个 sn-p 中的最后一个约束。

    【讨论】:

    • 谢谢@uraimo,我会试试的。
    • 它应该可以工作,我有一个与您发布的结构基本相同的应用程序。
    • 感谢这段代码:scrollView.addConstraint( NSLayoutConstraint(item: streamView, attribute: .Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0) ) 我基本上在那里。这不完全是您发布的内容(toItem: scrollView 而不是 toItem: streamView,但我认为这就是您的意思),但感谢您的推动!
    猜你喜欢
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 2020-07-20
    • 2013-05-01
    相关资源
    最近更新 更多