(Swift 5) UIScrollView 滚动但 none 的内容滚动(包括视频)

(Swift 5) UIScrollView scrolls but none of the content scrolls (video included)

我正在尝试学习在没有故事板的情况下构建视图。我试图建立一个滚动视图。在该滚动视图上有一个 UISearchBar、一个带有图像的 UIImageView 和一个 UILabel。它有效,但 none 的内容移动了。内容都被冻结在原地,就像无论我滚动多远,搜索栏都将始终位于页面顶部。和底部的图像。我附上了一段视频来说明我的意思。还有一个问题,因为 none 的内容是我想要的,但这是另一个问题。我意识到这可能是因为我对约束和自动布局以及在没有故事板的情况下构建视图了解不够。

Here's the video

class HomePageViewController: UIViewController {

var searchedText: String = ""
let label = UILabel()

let searchBar: UISearchBar = {
    let searchBar = UISearchBar()
    searchBar.placeholder = "Where are you going?"
    searchBar.translatesAutoresizingMaskIntoConstraints = false
    searchBar.barTintColor = .systemCyan
    searchBar.searchTextField.backgroundColor = .white
    searchBar.layer.cornerRadius = 5
    return searchBar
}()

let homeImage: UIImageView = {
    let homeImage = UIImageView()
    homeImage.translatesAutoresizingMaskIntoConstraints = false
    homeImage.clipsToBounds = true
    return homeImage
}()

let scrollView: UIScrollView = {
    let scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.backgroundColor = .systemMint
    scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 30)
    return scrollView
}()


override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .systemPink
 //        setupLayout()
 // tried this here doesn't do anything for me
}

func setupLayout() {
    view.addSubview(scrollView)
    self.scrollView.addSubview(searchBar)
    
    homeImage.image = UIImage(named: "Treehouse")
    self.scrollView.addSubview(homeImage)
    
    label.text = "Inspiration for your next trip..."
    self.scrollView.addSubview(label)
    // not sure where this label is being added I want it to be underneath the image but it isn't t
    
    let safeG = view.safeAreaLayoutGuide
    let viewFrame = view.bounds
    
    NSLayoutConstraint.activate([
        
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: -10),
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        
        searchBar.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 50.0),
        searchBar.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 0.9),
        searchBar.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
        
        homeImage.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 150),
        homeImage.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 1.1),
        homeImage.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
        homeImage.heightAnchor.constraint(equalToConstant: viewFrame.height/2),
        
        label.topAnchor.constraint(equalTo: homeImage.bottomAnchor, constant: 100)
    ])
 // was doing all this in viewDidLayoutSubviews but not sure if this is better place for it
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    setupLayout()
   // tried this in viewDidLoad() and it didn't solve it. 
}

}

如有任何帮助,我们将不胜感激

首先,在 UIScrollView 中限制子视图时,您应该将它们限制在滚动视图的 Content Layout Guide 中。您将它们限制在 视图的 安全区域布局指南中,因此它们永远不会去任何地方。

其次,很难在滚动视图中居中子视图,因为滚动视图可以水平和垂直滚动。所以它并没有真正的“中心”。

您可以将子视图放在堆栈视图中,或者,很常见的是,使用 UIView 作为“内容”视图来保存子视图。如果您将该内容视图的宽度限制为滚动视图的 Frame Layout Guide 宽度,则您可以水平居中子视图。

第三,评论您的约束非常有帮助,这样您就可以确切地知道您期望他们做什么。

这是您发布的代码的修改版本:

class HomePageViewController: UIViewController {
    
    var searchedText: String = ""
    
    let label: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    let searchBar: UISearchBar = {
        let searchBar = UISearchBar()
        searchBar.placeholder = "Where are you going?"
        searchBar.translatesAutoresizingMaskIntoConstraints = false
        searchBar.barTintColor = .systemCyan
        searchBar.searchTextField.backgroundColor = .white
        searchBar.layer.cornerRadius = 5
        return searchBar
    }()
    
    let homeImage: UIImageView = {
        let homeImage = UIImageView()
        homeImage.translatesAutoresizingMaskIntoConstraints = false
        homeImage.clipsToBounds = true
        return homeImage
    }()
    
    let scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.backgroundColor = .systemMint
        // don't do this
        //scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 30)
        return scrollView
    }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .systemPink

        setupLayout()
    }
    
    func setupLayout() {

        view.addSubview(scrollView)
        
        //homeImage.image = UIImage(named: "Treehouse")
        homeImage.image = UIImage(named: "natureBKG")
        
        label.text = "Inspiration for your next trip..."
        
        // let's use a UIView to hold the "scroll content"
        let contentView = UIView()
        contentView.translatesAutoresizingMaskIntoConstraints = false

        // give it a green background so we can see it
        contentView.backgroundColor = .green
        
        contentView.addSubview(searchBar)
        contentView.addSubview(homeImage)
        contentView.addSubview(label)

        scrollView.addSubview(contentView)
        
        let safeG = view.safeAreaLayoutGuide
        
        let svContentG = scrollView.contentLayoutGuide
        let svFrameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([

            // constrain scrollView to all 4 sides of view
            //  (generally, constrain to safe-area, but this is what you had)
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
            scrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            // constrain contentView to all 4 sides of scroll view's Content Layout Guide
            contentView.topAnchor.constraint(equalTo: svContentG.topAnchor, constant: 0.0),
            contentView.leadingAnchor.constraint(equalTo: svContentG.leadingAnchor, constant: 0.0),
            contentView.trailingAnchor.constraint(equalTo: svContentG.trailingAnchor, constant: 0.0),
            contentView.bottomAnchor.constraint(equalTo: svContentG.bottomAnchor, constant: 0.0),

            // constrain contentView Width equal to scroll view's Frame Layout Guide Width
            contentView.widthAnchor.constraint(equalTo: svFrameG.widthAnchor),

            // constrain searchBar Top to contentView Top + 50
            searchBar.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 50.0),
            
            // constrain searchBar Width to 90% of contentView Width
            searchBar.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.9),
            
            // constrain searchBar centerX to contentView centerX
            searchBar.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
            
            // constrain homeImage Top to searchBar Bottom + 40
            homeImage.topAnchor.constraint(equalTo: searchBar.bottomAnchor, constant: 40.0),

            // constrain homeImage Width equal to contentView Width
            homeImage.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 1.0),
            
            // constrain homeImage centerX to contentView centerX
            homeImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
            
            // constrain homeImage Height to 1/2 of scroll view frame Height
            homeImage.heightAnchor.constraint(equalTo: svFrameG.heightAnchor, multiplier: 0.5),

            // you probably won't get vertical scrolling yet, so increase the vertical space
            //  between the homeImage and the label by changing the constant
            //  from 100 to maybe 400
            
            // constrain label Top to homeImage Bottom + 100
            label.topAnchor.constraint(equalTo: homeImage.bottomAnchor, constant: 100.0),

            // constrain label centerX to contentView centerX
            label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),

            // constrain label Bottom to contentView Bottom - 20
            label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0),

        ])
    
    }
    
}