Swift:ScrollView 不滚动(如何设置约束)?

Posted

技术标签:

【中文标题】Swift:ScrollView 不滚动(如何设置约束)?【英文标题】:Swift: ScrollView not scrolling (how to set the constraints)? 【发布时间】:2018-06-26 14:06:18 【问题描述】:

我正在尝试在我的故事板中设置一个带有自动布局的滚动视图,并在代码中使用几个按钮填充它,但滚动视图不滚动,我不明白如何设置约束让滚动可用?

尤其是如何设置内容视图的约束(那是什么?)。

在情节提要中,滚动视图位于屏幕底部(距安全区域 20 像素)并从前导到尾随。它的大小为 375x80。

现在在代码中,这是滚动视图如何填充按钮以及如何设置的:

override func viewDidLoad() 
    super.viewDidLoad()

    var xCoord: CGFloat = 5
    var yCoord: CGFloat = 5
    let buttonWidth: CGFloat = 70
    let buttonHeight: CGFloat = 70
    let gapBetweenButtons: CGFloat = 5

    var itemCount = 0

    for i in 0..<CIFilterNames.count 
        itemCount = 1

        // Button properties
        let filterButton = UIButton(type: .custom)
        filterButton.frame = CGRect(x: xCoord, y: yCoord, width: buttonWidth, height: buttonHeight)
        filterButton.tag = itemCount
        filterButton.addTarget(self, action: #selector(ViewController.filterButtonTapped(sender:)), for: .touchUpInside)
        filterButton.layer.cornerRadius = 6
        filterButton.clipsToBounds = true

        //Code for filters will be added here

        let ciContext = CIContext(options: nil)
        let coreImage = CIImage(image: originalImage.image!)
        let filter = CIFilter(name: "\(CIFilterNames[i])")
        filter!.setDefaults()
        filter?.setValue(coreImage, forKey: kCIInputImageKey)
        let filteredImageDate = filter!.value(forKey: kCIOutputImageKey) as! CIImage
        let filteredImageRef = ciContext.createCGImage(filteredImageDate, from: filteredImageDate.extent)
        let imageForButton = UIImage(cgImage: filteredImageRef!)

        // Asign filtered image to the button
        filterButton.setBackgroundImage(imageForButton, for: .normal)

        // Add buttons in the scrollView
        xCoord += buttonWidth + gapBetweenButtons
        filterScrollView.addSubview(filterButton)

    

    filterScrollView.contentSize = CGSize(width: buttonWidth * CGFloat(itemCount + 2), height: yCoord)
    filterScrollView.isScrollEnabled = true



根据设备大小,显示 4 或 5 个按钮,但不会更多,并且无法滚动。

怎样才能让滚动成为可能?

【问题讨论】:

【参考方案1】:

原因在 itemCount 中,您将其设置为 itemCount + 2 将是 3 因为 itemCount 在 for 循环中为 1 所以,将其设置为等于数组大小

   filterScrollView.contentSize = CGSize(width: buttonWidth * CIFilterNames.count  , height: yCoord)

【讨论】:

【参考方案2】:

使用自动布局而不是计算尺寸会更好 - 为未来的更改提供更大的灵活性。

这是一个可以在 Playground 页面中运行的示例。我使用“计数”作为按钮标签,因为我没有你的图像。如果您添加图像,您可以取消注释相应的行并删除 .setTitle 和 .backgroundColor 行:

import UIKit
import PlaygroundSupport
import CoreImage

class TestViewController : UIViewController 

    var CIFilterNames = [
        "CIPhotoEffectChrome",
        "CIPhotoEffectFade",
        "CIPhotoEffectInstant",
        "CIPhotoEffectNoir",
        "CIPhotoEffectProcess",
        "CIPhotoEffectTonal",
        "CIPhotoEffectTransfer",
        "CISepiaTone"
    ]

    let buttonWidth: CGFloat = 70
    let buttonHeight: CGFloat = 70
    let gapBetweenButtons: CGFloat = 5

    override func viewDidLoad() 
        super.viewDidLoad()

        // create a UIScrollView
        let filterScrollView = UIScrollView()

        // we will set the auto-layout constraints
        filterScrollView.translatesAutoresizingMaskIntoConstraints = false

        // set background color so we can see the scrollView when the images are scrolled
        filterScrollView.backgroundColor = .orange

        // add the scrollView to the view
        view.addSubview(filterScrollView)

        // pin scrollView 20-pts from bottom/leading/trailing
        filterScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0).isActive = true
        filterScrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0).isActive = true
        filterScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20.0).isActive = true

        // scrollView height is 80
        filterScrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true

        // create a UIStackView
        let stackView = UIStackView()

        stackView.spacing = gapBetweenButtons

        // we will set the auto-layout constraints
        stackView.translatesAutoresizingMaskIntoConstraints = false

        // add the stackView to the scrollView
        filterScrollView.addSubview(stackView)

        // with auto-layout, scroll views use the content's constraints to
        // determine the contentSize,
        // so pin the stackView to top/bottom/leading/trailing of the scrollView
        // with padding to match the gapBetweenButtons
        stackView.leadingAnchor.constraint(equalTo: filterScrollView.leadingAnchor, constant: gapBetweenButtons).isActive = true
        stackView.topAnchor.constraint(equalTo: filterScrollView.topAnchor, constant: gapBetweenButtons).isActive = true
        stackView.trailingAnchor.constraint(equalTo: filterScrollView.trailingAnchor, constant: -gapBetweenButtons).isActive = true
        stackView.bottomAnchor.constraint(equalTo: filterScrollView.bottomAnchor, constant: -gapBetweenButtons).isActive = true

        // loop through the images
        for i in 0..<CIFilterNames.count 

            // create a new UIButton
            let filterButton = UIButton(type: .custom)
            filterButton.tag = i

            // we will set the auto-layout constraints, and allow the stackView
            // to handle the placement
            filterButton.translatesAutoresizingMaskIntoConstraints = false

            // set the width and height constraints
            filterButton.widthAnchor.constraint(equalToConstant: buttonWidth).isActive = true
            filterButton.heightAnchor.constraint(equalToConstant: buttonHeight).isActive = true

            filterButton.layer.cornerRadius = 6
            filterButton.clipsToBounds = true

            filterButton.addTarget(self, action: #selector(filterButtonTapped(_:)), for: .touchUpInside)

            // this example doesn't have your images, so
            // set button title and background color
            filterButton.setTitle("\(i)", for: .normal)
            filterButton.backgroundColor = .blue

//          //Code for filters will be added here
//          
//          let ciContext = CIContext(options: nil)
//          let coreImage = CIImage(image: originalImage.image!)
//          let filter = CIFilter(name: "\(CIFilterNames[i])")
//          filter!.setDefaults()
//          filter?.setValue(coreImage, forKey: kCIInputImageKey)
//          let filteredImageDate = filter!.value(forKey: kCIOutputImageKey) as! CIImage
//          let filteredImageRef = ciContext.createCGImage(filteredImageDate, from: filteredImageDate.extent)
//          let imageForButton = UIImage(cgImage: filteredImageRef!)
//          
//          // Asign filtered image to the button
//          filterButton.setBackgroundImage(imageForButton, for: .normal)


            // add the image view to the stackView
            stackView.addArrangedSubview(filterButton)

        

    

    func filterButtonTapped(_ sender: Any?) -> Void 
        if let b = sender as? UIButton 
            print("Tapped:", b.tag)
        
    



let vc = TestViewController()
vc.view.backgroundColor = .red
PlaygroundPage.current.liveView = vc

【讨论】:

以上是关于Swift:ScrollView 不滚动(如何设置约束)?的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 如何对 ScrollView 中的项目使用自动布局?

Swift iOS以编程方式在导航栏下方设置scrollView约束

Swift - ScrollView 中的 StackView 不滚动

UITableViewCell中的Swift ScrollView不滚动

Xcode ScrollView不滚动

如何设置scrollView 横向滚动