【问题标题】:Swift ScrollView Layout Issue With PageController and Images iOSPageController 和图像 iOS 的 Swift ScrollView 布局问题
【发布时间】:2020-12-19 02:06:36
【问题描述】:

我不知道如何为带有 imageView 的 scrollView 设置约束。 我正在使用带有 pageConroller 的 scrollView 来浏览一堆图像。

在下图中查看我的布局。

// imageView的代码

for index in 0..<drinksImagesArray.count {
        frame.origin.x = scrollView.frame.size.width * CGFloat(index)
        frame.size = scrollView.frame.size
        
        let imageView = UIImageView(frame: frame)
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: imagesArray[index].name)
        self.scrollView.addSubview(imageView)
    }
    scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(imagesArray.count), height: scrollView.frame.size.height)
    scrollView.delegate = self

有什么建议吗?谢谢!

Layout

【问题讨论】:

    标签: ios swift uiscrollview scrollview uipagecontrol


    【解决方案1】:

    使用自动布局会让你的运气更好 --- 它可以为你处理所有的帧大小和.contentSize

    这是一个简单的示例 - 它使用了一个视图控制器,并在 Storyboard 中添加了一个滚动视图,因此您应该很容易与您的代码集成:

    class ScrollingImagesViewController: UIViewController {
        
        @IBOutlet var scrollView: UIScrollView!
        
        var drinksImagesArray: [String] = []
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // however you're populating your array...
            drinksImagesArray = [
                "drink1",
                "drink2",
                "drink3",
                // etc...
            ]
    
            // create a horizontal stack view
            let stack = UIStackView()
            stack.axis = .horizontal
            stack.alignment = .fill
            stack.distribution = .fillEqually
            stack.spacing = 0
    
            // add the stack view to the scroll view
            stack.translatesAutoresizingMaskIntoConstraints = false
            scrollView.addSubview(stack)
            
            // use scroll view's contentLayoutGuide for content constraints
            let svCLG = scrollView.contentLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // stack view constrained Top / Bottom / Leading / Trailing of scroll view CONTENT guide
                stack.topAnchor.constraint(equalTo: svCLG.topAnchor),
                stack.bottomAnchor.constraint(equalTo: svCLG.bottomAnchor),
                stack.leadingAnchor.constraint(equalTo: svCLG.leadingAnchor),
                stack.trailingAnchor.constraint(equalTo: svCLG.trailingAnchor),
                
                // stack view height == scroll view FRAME height
                stack.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),
                
            ])
    
            // create image views and add them to the stack view
            drinksImagesArray.forEach { imgName in
                let v = UIImageView()
                v.backgroundColor = .lightGray
                v.contentMode = .scaleAspectFit
                // make sure we load a valid image
                if let img = UIImage(named: imgName) {
                    v.image = img
                }
                stack.addArrangedSubview(v)
            }
            
            // stack distribution is set to .fillEqually, so we only need to set the
            // width constraint on the first image view
            
            // unwrap it
            if let firstImageView = stack.arrangedSubviews.first {
                firstImageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
            }
            
        }
    
    }
    

    编辑

    查看故事板后...

    当您添加 UINavigationBarUIToolbarUIScrollView 作为子视图时,自动布局似乎不喜欢它。特别是,它似乎混淆了滚动视图的框架相关约束。

    解决方法是首先为滚动视图添加约束:

    • 从顶部到导航栏底部
    • 底部到页面控件顶部
    • 领先和尾随到安全区域

    故事板/界面生成器会抱怨滚动视图配置不正确。您可以忽略它,或者选择滚动视图并将歧义设置为从不验证:

    然后,在您的视图控制器类中,我们需要为要添加到滚动视图的堆栈视图创建高度约束,并在viewDidLayoutSubviews() 中设置该高度常量。

    这是完整的代码:

    //
    //  WasserhaushaltViewController.swift
    //  deSynthTheOceans
    //
    //  Created by robinsonhus0 on 24.03.20.
    //  Copyright © 2020 robinsonhus0. All rights reserved.
    //
    
    import UIKit
    import AVFoundation
    import Charts
    import FSCalendar
    import HealthKit
    
    
    struct WasserSpeicher: Codable {
        let wassermenge: Double
        let speicherdatum: String
        let speicherStelle: Double
    }
    
    class WasserhaushaltViewController: UIViewController, UIScrollViewDelegate {
        @IBOutlet weak var diagrammView: UIView!
        @IBOutlet weak var scrollView: UIScrollView!
        @IBOutlet weak var pageControl: UIPageControl!
        
        let drinksImagesArray = ["tapWater", "water", "milk", "cola", "coffee", "tea", "juice", "beer"]
    
        var imageIndex = Int()
        
        struct Drinks {
            var name: String
            var tagesMengeFactor: Double
            var gesamtMengeFactor: Double
        }
        
        var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        var pageNumber = CGFloat()
        
        @IBOutlet weak var todaysWaterConsumptionLabel: UILabel!
        @IBOutlet weak var waterGoalProgress: UIProgressView!
        @IBOutlet weak var waterGoalLabel: UILabel!
        @IBOutlet weak var wasserMengeStepper: UIStepper!
        @IBOutlet weak var motivationTextView: UITextView!
        @IBOutlet weak var wasserglasButton: UIBarButtonItem!
        @IBOutlet weak var kleineFlascheButton: UIBarButtonItem!
        @IBOutlet weak var grosseFlascheButton: UIBarButtonItem!
        @IBOutlet weak var overAllWaterConsumptionLabel: UILabel!
        
        // added
        let scrollingImagesStackView = UIStackView()
        var stackHeightConstraint: NSLayoutConstraint!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            pageControl.numberOfPages = drinksImagesArray.count
            setupDrinkImages()
        }
        
        
        func setupDrinkImages() {
            // set stack view properties
            scrollingImagesStackView.axis = .horizontal
            scrollingImagesStackView.alignment = .fill
            scrollingImagesStackView.distribution = .fillEqually
            scrollingImagesStackView.spacing = 0
            
            // add the stack view to the scroll view
            scrollingImagesStackView.translatesAutoresizingMaskIntoConstraints = false
            scrollView.addSubview(scrollingImagesStackView)
            
            // use scroll view's contentLayoutGuide for content constraints
            let svCLG = scrollView.contentLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // stack view constrained Top / Bottom / Leading / Trailing of scroll view CONTENT guide
                scrollingImagesStackView.topAnchor.constraint(equalTo: svCLG.topAnchor),
                scrollingImagesStackView.bottomAnchor.constraint(equalTo: svCLG.bottomAnchor),
                scrollingImagesStackView.leadingAnchor.constraint(equalTo: svCLG.leadingAnchor),
                scrollingImagesStackView.trailingAnchor.constraint(equalTo: svCLG.trailingAnchor),
                
            ])
            
            // create the stack view height constraint - it will be updated in viewDidLayoutSubviews
            stackHeightConstraint = scrollingImagesStackView.heightAnchor.constraint(equalToConstant: 0)
            stackHeightConstraint.isActive = true
            
            // create image views and add them to the stack view
            drinksImagesArray.forEach { imgName in
                let v = UIImageView()
                v.backgroundColor = .orange
                v.contentMode = .scaleAspectFit
                // make sure we load a valid image
                if let img = UIImage(named: imgName) {
                    v.image = img
                }
                scrollingImagesStackView.addArrangedSubview(v)
            }
            
            // stack distribution is set to .fillEqually, so we only need to set the
            // width constraint on the first image view
            
            // unwrap it
            if let firstImageView = scrollingImagesStackView.arrangedSubviews.first {
                firstImageView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
            }
    
            scrollView.delegate = self
        }
        
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            
            // since we have a UINavigationBar and a UIToolBar in the view hierarchy,
            //  we need to set this here
            //  Note: if the view size changes
            // stack view height == scroll view FRAME height
            stackHeightConstraint.constant = scrollView.frame.height
            
        }
        
    //  func setupDrinkImages() {
    //      for index in 0..<drinksImagesArray.count {
    //          frame.origin.x = scrollView.frame.size.width * CGFloat(index)
    //          frame.size = scrollView.frame.size
    //
    //          let imageView = UIImageView(frame: frame)
    //          imageView.contentMode = .scaleAspectFit
    //          imageView.image = UIImage(named: drinksImagesArray[index])
    //          self.scrollView.addSubview(imageView)
    //      }
    //      scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(drinksImagesArray.count), height: scrollView.frame.size.height)
    //      scrollView.delegate = self
    //  }
        
        func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
            pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
            pageControl.currentPage = Int(pageNumber)
        }
    }
    

    您的(修改后的)故事板太大,无法在此处添加...如果您对上述更改有任何疑问,请点击此处:https://pastebin.com/2Q1uFUgL

    【讨论】:

    • 非常感谢!太好了,但现在图像与 Navigationcontroller 和 pagecontrol 重叠。
    • 这没有多大意义...为了使图像重叠 超出滚动视图范围,您必须设置 scrollView.clipsToBounds = false 和 se堆栈视图的高度大于滚动视图框架的高度。如果您将 Storyboard 的 源代码 和您在 pastebin.com 上使用的代码发布,我会看一看。
    • @JcbPrn - 即使我们尝试使用 teamView,我也会要求同样的事情......只需在 pastebin.com 上发布您的 Storyboard 源代码和您的课程代码(或将您的整个项目放在GitHub)。
    • 这里是故事板:pastebin.com/5uwBcxPB,这是我的 Swift 代码:pastebin.com/0Atmzn8B 谢谢你这么快的回答
    • @JcbPrn - 请参阅我的答案底部的 编辑
    猜你喜欢
    • 2012-09-12
    • 2017-10-15
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多