繁体   English   中英

在 Swift 3 中以编程方式使用 ScrollView

[英]Using ScrollView Programmatically in Swift 3

我已经搜索了其他问题,但似乎仍然在使用 swift 3 中的自动布局以编程方式创建我的 scrollView 时遇到一些问题。我能够让我的 scrollview 显示如下图所示,但是当我滚动到底部时,我的其他标签确实显示了不会出现,并且“滚动顶部”标签不会消失。

滚动视图

希望有人可以帮助查看下面的代码!

import UIKit

class ViewController: UIViewController {

let labelOne: UILabel = {
    let label = UILabel()
    label.text = "Scroll Top"
    label.backgroundColor = .red
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

let labelTwo: UILabel = {
    let label = UILabel()
    label.text = "Scroll Bottom"
    label.backgroundColor = .green
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()


override func viewDidLoad() {
    super.viewDidLoad()

    let screensize: CGRect = UIScreen.main.bounds
    let screenWidth = screensize.width
    let screenHeight = screensize.height
    var scrollView: UIScrollView!
    scrollView = UIScrollView(frame: CGRect(x: 0, y: 120, width: screenWidth, height: screenHeight))
    scrollView.contentSize = CGSize(width: screenWidth, height: 2000)
    scrollView.addSubview(labelOne)
    scrollView.addSubview(labelTwo)


    view.addSubview(labelOne)
    view.addSubview(labelTwo)
    view.addSubview(scrollView)

    // Visual Format Constraints
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[v0]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": labelOne]))
    view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-100-[v0]", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0": labelOne]))

    // Using iOS 9 Constraints in order to place the label past the iPhone 7 view
    view.addConstraint(NSLayoutConstraint(item: labelTwo, attribute: .top, relatedBy: .equal, toItem: labelOne, attribute: .bottom, multiplier: 1, constant: screenHeight + 200))
    view.addConstraint(NSLayoutConstraint(item: labelTwo, attribute: .right, relatedBy: .equal, toItem: labelOne, attribute: .right, multiplier: 1, constant: 0))
    view.addConstraint(NSLayoutConstraint(item: labelTwo, attribute: .left, relatedBy: .equal, toItem: labelOne, attribute: .left, multiplier: 1, constant: 0)     

    }

}

使用约束来定义滚动内容的大小很容易——因此您不必进行任何手动计算。

只记得:

  1. 滚动视图的内容元素必须具有 left / top / width / height 值。 对于标签等对象,它们具有固有尺寸,因此您只需定义左侧和顶部。
  2. 滚动视图的内容元素定义了可滚动区域的边界 - contentSize - 但它们是通过底部和右侧约束来实现的。
  3. 结合这两个概念,您会发现您需要一个“连续链”,其中至少有一个元素定义了顶部/左侧/底部/右侧范围。

这是一个简单的示例,它将直接在 Playground 页面中运行:

import UIKit
import PlaygroundSupport

class TestViewController : UIViewController {

    let labelOne: UILabel = {
        let label = UILabel()
        label.text = "Scroll Top"
        label.backgroundColor = .red
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let labelTwo: UILabel = {
        let label = UILabel()
        label.text = "Scroll Bottom"
        label.backgroundColor = .green
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .cyan
        return v
    }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // add the scroll view to self.view
        self.view.addSubview(scrollView)
        
        // constrain the scroll view to 8-pts on each side
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
        
        // add labelOne to the scroll view
        scrollView.addSubview(labelOne)
        
        // constrain labelOne to left & top with 16-pts padding
        // this also defines the left & top of the scroll content
        labelOne.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 16.0).isActive = true
        labelOne.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 16.0).isActive = true
        
        // add labelTwo to the scroll view
        scrollView.addSubview(labelTwo)
        
        // constrain labelTwo at 400-pts from the left
        labelTwo.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 400.0).isActive = true

        // constrain labelTwo at 1000-pts from the top
        labelTwo.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 1000).isActive = true
        
        // constrain labelTwo to right & bottom with 16-pts padding
        labelTwo.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -16.0).isActive = true
        labelTwo.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -16.0).isActive = true
        
    }
    
}


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

编辑——因为这个答案仍然偶尔会受到关注,我更新了代码以使用更现代的语法,尊重安全区域,并使用滚动视图的.contentLayoutGuide

class TestViewController : UIViewController {
    
    let labelOne: UILabel = {
        let label = UILabel()
        label.text = "Scroll Top"
        label.backgroundColor = .yellow
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let labelTwo: UILabel = {
        let label = UILabel()
        label.text = "Scroll Bottom"
        label.backgroundColor = .green
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .cyan
        return v
    }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // add the scroll view to self.view
        self.view.addSubview(scrollView)

        // add labelOne to the scroll view
        scrollView.addSubview(labelOne)
        
        // add labelTwo to the scroll view
        scrollView.addSubview(labelTwo)
        
        // always a good idea to respect safe area
        let safeG = view.safeAreaLayoutGuide
        
        // we want to constrain subviews to the scroll view's Content Layout Guide
        let contentG = scrollView.contentLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain the scroll view to safe area with 8-pts on each side
            scrollView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 8.0),
            scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 8.0),
            scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -8.0),
            scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -8.0),
            
            // constrain labelOne to leading & top of Content Layout Guide with 16-pts padding
            // this also defines the left & top of the scroll content
            labelOne.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 16.0),
            labelOne.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 16.0),

            // constrain labelTwo leading at 400-pts from labelOne trailing
            labelTwo.leadingAnchor.constraint(equalTo: labelOne.trailingAnchor, constant: 400.0),
            
            // constrain labelTwo top at 1000-pts from the labelOne bottom
            labelTwo.topAnchor.constraint(equalTo: labelOne.bottomAnchor, constant: 1000),
            
            // constrain labelTwo to trailing & bottom of Content Layout Guide with 16-pts padding
            // this also defines the right & bottom of the scroll content
            labelTwo.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: -16.0),
            labelTwo.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: -16.0),
            
        ])
        
    }
    
}

两件事情。

1.将标签添加到滚动视图,而不是您的视图

您希望您的标签随滚动视图一起滚动,那么您不应该将它添加到您的视图中。 运行代码时,您可以滚动,但那里的固定标签固定在您的视图上,而不是在滚动视图上

2.确保你正确地添加了你的约束

在您的故事板上尝试了解哪种约束组合足以用于视图。 一个标签至少需要 4 个约束条件。

底线

这是您的代码的修改版本。 对于约束,我添加了 padding left、padding top、width 和 height,它起作用了。 我的代码是

let labelOne: UILabel = {
    let label = UILabel()
    label.text = "Scroll Top"
    label.backgroundColor = .red
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

let labelTwo: UILabel = {
    let label = UILabel()
    label.text = "Scroll Bottom"
    label.backgroundColor = .green
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()


override func viewDidLoad() {
    super.viewDidLoad()

    let screensize: CGRect = UIScreen.main.bounds
    let screenWidth = screensize.width
    let screenHeight = screensize.height
    var scrollView: UIScrollView!
    scrollView = UIScrollView(frame: CGRect(x: 0, y: 120, width: screenWidth, height: screenHeight))

    scrollView.addSubview(labelTwo)

    NSLayoutConstraint(item: labelTwo, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leadingMargin, multiplier: 1, constant: 10).isActive = true
    NSLayoutConstraint(item: labelTwo, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 200).isActive = true
    NSLayoutConstraint(item: labelTwo, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .topMargin, multiplier: 1, constant: 10).isActive = true
    NSLayoutConstraint(item: labelTwo, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 30).isActive = true

    scrollView.contentSize = CGSize(width: screenWidth, height: 2000)
    view.addSubview(scrollView)

}

滚动视图看起来像这样

在此处输入图像描述

对我来说,这项工作很有魅力

class WithDrawConfirmationViewController: UIViewController, WithDrawConfirmationViewProtocol {

    var presenter: WithDrawConfirmationPresenterProtocol?
    private let viewbackgroundColor = UIColor(hexString: "#F5F5F8")
    // MARK:- View properties
    lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        //view.backgroundColor = .red
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        return scrollView
    }()
    
    lazy var contentView: UIView = {
        let view = UIView()
        //view.backgroundColor = .green
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    lazy var headerView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    private lazy var titleLabel:UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.themeBlack
        label.text = "Withdraw Confirmation"//"Loading.."
        label.textAlignment = .center
        label.font = UIFont(name: "AvenirNext-DemiBold", size: 20)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        return label
    }()
    
    
    private lazy var descriptionLabel:UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.themeGray
        label.text = "Please confirm your fixed deposit details before withdrawing your deposit"// "Loading.."
        label.textAlignment = .center
        label.font = UIFont(name: "AvenirNext-Medium", size: 14)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.setContentHuggingPriority(1000, for: .vertical)
        return label
    }()
    
    private lazy var instructionLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.themeGray
        label.text = "Complete fixed deposit will be withdrawn and the money will be debited to your account within 1-2 working days."//"Loading.."
        label.textAlignment = .left
        label.font = UIFont(name: "AvenirNext-Medium", size: 14)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        return label
    }()
    
    private lazy var warningLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.textColor = UIColor.themeBlue
        label.text = "Axis bank will levy a penalty of 1% - 2% for premature withdrawal"//"Loading.."
        label.textAlignment = .left
        label.font = UIFont(name: "AvenirNext-DemiBold", size: 13)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        return label
    }()
    
    private lazy var warningView: UIView = {
        let view = UIView()
        view.cornerradius = 5
        view.backgroundColor = UIColor(hexFromString: "#E8F4FD")
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    private lazy var fdInformationDetailView: FDPurchaseDetailView = {
        let view = FDPurchaseDetailView(isPoweredByViewVisible: false)
        //view.backgroundColor = .red
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    private lazy var footerCTAView: FooterButtonViewView = {
        let view = FooterButtonViewView()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    // MARK:- Life cycle
    override func viewDidLoad() {
        super.viewDidLoad()
        contentView.backgroundColor = viewbackgroundColor
        scrollView.backgroundColor = viewbackgroundColor
        setUpUI()
        presenter?.viewDidLoadTriggered()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    }
    
    private func setUpUI() {
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)
        view.backgroundColor = viewbackgroundColor
        addFooter()
        setUpHeaderView()
        setUpFDDetailView()
        setUpInformationAndWarningView()
        //scrollView.backgroundColor = .lightGray
        scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: footerCTAView.topAnchor).isActive = true
        scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 100, right: 0)
        
        contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
        contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
        contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
        //contentView.bottomAnchor.constraint(equalTo: footerCTAView.topAnchor).isActive = true
    }
    
    private func setUpHeaderView() {
        contentView.addSubview(headerView)
        headerView.addSubviews([titleLabel, descriptionLabel])
        
        headerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
        headerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
        headerView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4).isActive = true
       
        titleLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8).isActive = true
        titleLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
        titleLabel.topAnchor.constraint(equalTo: headerView.topAnchor, constant: 8).isActive = true
        
        descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant:  20).isActive = true
        descriptionLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8).isActive = true
        descriptionLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
        descriptionLabel.bottomAnchor.constraint(equalTo: headerView.bottomAnchor, constant: -20).isActive = true
    }
    
    
    private func setUpFDDetailView() {
        contentView.addSubview(fdInformationDetailView)
        fdInformationDetailView.topAnchor.constraint(equalTo: headerView.bottomAnchor).isActive = true
        fdInformationDetailView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
        fdInformationDetailView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
       
    }
    
    private func setUpInformationAndWarningView() {
        contentView.addSubview(instructionLabel)
        
        instructionLabel.topAnchor.constraint(equalTo: fdInformationDetailView.bottomAnchor, constant: 20).isActive = true
        instructionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
        instructionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
        
        warningView.addSubview(warningLabel)
        warningLabel.topAnchor.constraint(equalTo: warningView.topAnchor, constant: 8).isActive = true
        warningLabel.leadingAnchor.constraint(equalTo: warningView.leadingAnchor, constant: 20).isActive = true
        warningLabel.trailingAnchor.constraint(equalTo: warningView.trailingAnchor, constant: -20).isActive = true
        warningLabel.bottomAnchor.constraint(equalTo: warningView.bottomAnchor, constant: -8).isActive = true
        
        contentView.addSubview(warningView)
        
        warningView.topAnchor.constraint(equalTo: instructionLabel.bottomAnchor, constant: 8).isActive = true
        warningView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20).isActive = true
        warningView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20).isActive = true
       //warningView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
        warningView.bottomAnchor.constraint(greaterThanOrEqualTo: contentView.bottomAnchor, constant: -20).isActive = true
        
    }
    
    private func addFooter() {
        view.addSubview(footerCTAView)
        footerCTAView.delegate = self
        footerCTAView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        footerCTAView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        footerCTAView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
    }
}

将滚动视图图像设置为墙纸:

@IBOutlet var scroll_view_img: UIScrollView!

var itemPhotoList = NSMutableArray()

var button = NSMutableArray()    

@IBOutlet var imageview_big: UIImageView!

override func viewDidLoad() {

    super.viewDidLoad()
    itemPhotoList = ["grief-and-loss copy.jpg","aaa.jpg","image_4.jpeg"]        

    // button = ["btn1","btn2"]

    let width:CGFloat = 100
    let height:CGFloat = 100
    var xposition:CGFloat = 10
    var scroll_contont:CGFloat = 0

    for i in 0 ..< itemPhotoList.count
    {
        var button_img = UIButton()
        button_img = UIButton(frame: CGRect(x: xposition, y: 50, width: width, height: height))
        let img = UIImage(named:itemPhotoList[i] as! String)
        button_img.setImage(img, for: .normal)
        scroll_view_img.addSubview(button_img)
        button_img.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        button_img.tag = i
        view.addSubview(scroll_view_img)
        xposition += width+10
        scroll_contont += width
        scroll_view_img.contentSize = CGSize(width: scroll_contont, height: height)
    }
}

func buttonAction(sender: UIButton!)
{
    switch sender.tag {
    case 0:
        imageview_big.image = UIImage(named: "grief-and-loss copy.jpg")
    case 1:
        imageview_big.image = UIImage(named: "aaa.jpg")
    case 2:
        imageview_big.image = UIImage(named: "image_4.jpeg")
    default:
        break
    }
}

将此控制器复制并粘贴到您的项目中

class BaseScrollViewController: UIViewController {

lazy var contentViewSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 100)
lazy var scrollView: UIScrollView = {
    let view = UIScrollView(frame: .zero)
    view.backgroundColor = .white
    view.frame = self.view.bounds
    view.contentSize = contentViewSize
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()
lazy var containerView: UIView = {
    let v = UIView()
    v.backgroundColor = .white
    v.frame.size = contentViewSize
    return v
}()

override func viewDidLoad() {
    view.backgroundColor = .white
    view.addSubview(scrollView)
    scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

    scrollView.addSubview(containerView)
    setupContainer(containerView)
    super.viewDidLoad()
    
}

public func setupContainer(_ container: UIView) {
    
}

}

以上代码的用法:

class ClientViewController: BaseScrollViewController {
override func viewDidLoad() {
    super.viewDidLoad()
    // do your stuff here
}

override func setupContainer(_ container: UIView) {
    // add views here
}

}

这些答案不适用于导航栏中的大标题。 确保在视图控制器的 viewDidLoad() 方法中包含以下代码:

self.navigationController?.navigationBar.prefersLargeTitles = false

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM