(Swift 5) UIScrollView 滚动但没有内容滚动(包括视频)

发布于 2025-01-12 14:44:11 字数 3239 浏览 1 评论 0原文

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

这是视频

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. 
}

}

任何帮助将不胜感激

I'm trying to learn to build views without storyboard. I tried to build a scrollview. On that scrollview is a UISearchBar, a UIImageView with an image and a UILabel. It works but none of the content moves. The content is all just frozen in place like no matter how far I scroll the search bar will always be on top of the page. and the image on the bottom. I've attached a video to show what I mean. There's also a problem because none of the content is where I want it to be but that's another problem. I realize this is probably because I don't know enough about constraints and autolayout and building views without storyboards.

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. 
}

}

any help would be appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苏佲洛 2025-01-19 14:44:12

首先,在 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),

        ])
    
    }
    
}

First, when constraining subviews in a UIScrollView, you should constrain them to the scroll view's Content Layout Guide. You're constraining them to the view's safe area layout guide, so they're never going to go anywhere.

Second, it's difficult to center subviews in a scroll view, because the scroll view can scroll both horizontally and vertically. So it doesn't really have a "center."

You can either put subviews in a stack view, or, quite common, use a UIView as a "content" view to hold the subviews. If you constrain that content view's Width to the scroll view's Frame Layout Guide width, you can then horizontally center the subviews.

Third, it can be very helpful to comment your constraints, so you know exactly what you expect them to do.

Here's a modified version of your posted code:

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),

        ])
    
    }
    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文