【问题标题】:UIImageView cuts inside UIScrollViewUIImageView 切入 UIScrollView
【发布时间】:2021-06-11 19:21:10
【问题描述】:

我正在尝试使用包含多个UIImageView 的UIStackView 使用此代码创建UIScrollView:

let stackView = UIStackView(frame: .zero)

scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .green
scrollView.showsHorizontalScrollIndicator = false
scrollView.delegate = self

self.view.addSubview(scrollView)


scrollView.anchor(top: textSV.bottomAnchor, leading: self.view.safeAreaLayoutGuide.leadingAnchor, bottom: anotherView?.topAnchor, trailing: self.view.safeAreaLayoutGuide.trailingAnchor)
scrollView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true

scrollView.contentInsetAdjustmentBehavior = .never

stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.distribution = .equalSpacing
stackView.spacing = 0

scrollView.addSubview(stackView)
stackView.fillSuperview()

for _ in 1...8 {
    let pageView = UIImageView(image: UIImage(named: "iphone12mockup"))
    pageView.clipsToBounds = true
    pageView.contentMode = .scaleAspectFit

    pageView.translatesAutoresizingMaskIntoConstraints = false
    stackView.addArrangedSubview(pageView)

    pageView.anchor(top: stackView.topAnchor, leading: nil, bottom: stackView.bottomAnchor, trailing: nil)
}

问题是 UIImageView 没有调整到scaleAspectFit 并且看起来像这样(看不到完整图像):

编辑

let img = UIImage(named: "iphone12mockup")
let width = img?.size.width

let pageView = UIImageView(image: img)
pageView.clipsToBounds = true
pageView.contentMode = .scaleAspectFit

pageView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(pageView)

pageView.anchor(top: stackView.topAnchor, leading: nil, bottom: stackView.bottomAnchor, trailing: nil)
pageView.widthAnchor.constraint(equalToConstant: width!).isActive = true

【问题讨论】:

  • 如果您不希望 UIImageView 水平滚动,您需要明确设置它的宽度,因为在滚动视图中没有“适合”的内容。
  • @ClausJørgensen 我更新了我的代码,我仍然得到相同的结果(你可以在我的帖子下看到编辑)
  • 您将其限制为图像宽度 - 这不会改变任何内容。您需要将其限制为滚动视图容器的宽度(即您现在使用 UIScreen.main.bounds.width 所做的事情)。滚动视图的全部意义在于您可以在其中包含更大的内容以供滚动,因此如果您不限制至少一个维度,则不能指望图像不会占用所有必要的空间。
  • 另外你真的不应该使用UIScreen.main.bounds.width 来限制宽度,这是a) 不好的做法,并且b) 当你旋转设备时会失败。只需将其限制为self.view.safeAreaLayoutGuide.widthAnchor,这样您就可以在横向模式下获得安全的插图(即滚动视图不会落后于缺口)
  • @ClausJørgensen 我希望该图像视图彼此相邻且无需分页,并且我希望它们适合滚动视图高度

标签: ios swift objective-c uiview uikit


【解决方案1】:

您想利用滚动视图的内容和框架布局指南...

  • 将堆栈视图的所有 4 面都限制在滚动视图的内容布局指南中
  • 将堆栈视图的高度限制为滚动视图的框架布局指南

对于您添加到堆栈视图的每个图像视图:

  • 将图像视图的宽度限制为滚动视图的框架布局指南

这是一个完整的例子:

class ViewController: UIViewController, UIScrollViewDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // just trying to include what you've shown
        let textSV = UILabel()
        textSV.backgroundColor = .yellow
        textSV.text = "textSV"
        textSV.textAlignment = .center
        
        let anotherView = UILabel()
        anotherView.backgroundColor = .cyan
        anotherView.text = "anotherView"
        anotherView.textAlignment = .center
        
        [textSV, anotherView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }
        
        // respect safe area
        let safeG = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            textSV.topAnchor.constraint(equalTo: safeG.topAnchor),
            textSV.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            textSV.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            textSV.heightAnchor.constraint(equalToConstant: 60.0),

            anotherView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            anotherView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            anotherView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),
            anotherView.heightAnchor.constraint(equalToConstant: 60.0),
        ])

        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.backgroundColor = .green
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.delegate = self

        view.addSubview(scrollView)
        
        // use a stack view to hold and arrange the scrollView's subviews
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        // add the stackView to the scrollView
        scrollView.addSubview(stackView)
        
        // use scrollView's Content Layout Guide to define scrollable content
        let layoutG = scrollView.contentLayoutGuide
        
        // use scrollView's Frame Layout Guide to define content height (since you want horizontal scrolling)
        let frameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([

            // constrain scrollView Top to textSV Bottom
            scrollView.topAnchor.constraint(equalTo: textSV.bottomAnchor),
            
            // constrain scrollView Leading/Trailing to safe area
            scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            
            // constrain scrollView Bottom to anotherView Top
            scrollView.bottomAnchor.constraint(equalTo: anotherView.topAnchor),
            
            // constrain all 4 sides of the stackView to scrollView's Content Layout Guide
            stackView.topAnchor.constraint(equalTo: layoutG.topAnchor),
            stackView.bottomAnchor.constraint(equalTo: layoutG.bottomAnchor),
            stackView.leadingAnchor.constraint(equalTo: layoutG.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: layoutG.trailingAnchor),
            
            // constrain stackView's height to scrollView's Frame Layout Guide height
            stackView.heightAnchor.constraint(equalTo: frameG.heightAnchor),
            
        ])
        
        // add imageViews to the stack view
        for _ in 1...8 {
            let pageView = UIImageView(image: UIImage(named: "iphone12mockup"))
            //let pageView = UIImageView(image: UIImage(named: "sample"))
            // set image view background color so you can
            //  see its frame (since the image will be aspect-fit scaled)
            pageView.backgroundColor = .systemYellow
            pageView.contentMode = .scaleAspectFit
            // add it to the stack view
            stackView.addArrangedSubview(pageView)
            // constrain its Width to scrollView's Frame Layout Guide Width
            pageView.widthAnchor.constraint(equalTo: frameG.widthAnchor).isActive = true
        }

    }
    
}

在启动时(在 iPhone 8 上)如下所示:

向右滚动一点后:

请注意,由于您希望将图像视图设置为Aspect Fit,因此我将“pageView”图像视图的背景颜色设置为.systemYellow,这样您就可以看到 imageView 框架填充了滚动视图框架的宽度和高度。


编辑 -- 如果您希望图像与其高度成比例,而没有“两侧的空白空间”,您需要设置与高度成比例的图像视图宽度约束,基于图片大小。

用这个替换“添加图像视图”循环:

    // add imageViews to the stack view
    for _ in 1...8 {
        guard let img = UIImage(named: "iphone12mockup") else {
            fatalError("Could not load image!")
        }
        let pageView = UIImageView()
        pageView.image = img
        pageView.contentMode = .scaleToFill
        // add it to the stack view
        stackView.addArrangedSubview(pageView)
        // constrain its Width proportional to the image height
        pageView.widthAnchor.constraint(equalTo: pageView.heightAnchor, multiplier: img.size.width / img.size.height).isActive = true
    }

输出将是:

向右滚动一点后:

【讨论】:

  • 谢谢!但是有一个问题,我希望图像视图之间没有任何空间
  • @YosiFZ - 请参阅我的回答中的 Edit。
猜你喜欢
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-29
  • 2016-03-19
相关资源
最近更新 更多