【问题标题】:try to set up a Dynamic UIScrollView programmatically but met problem尝试以编程方式设置 Dynamic UIScrollView 但遇到问题
【发布时间】:2020-09-21 08:44:09
【问题描述】:

最近我尝试根据这个网站设置一个动态的UIScrollView:https://medium.com/@javedmultani16/uiscrollview-dynamic-content-size-through-storyboard-in-ios-fb873e9278e

我试着一步一步做,但似乎我误解了什么,但我想不通。这是我的代码,我尝试添加 30 UITextField 并将 UIScrollView 设置为与这些内容相等的高度。

我遇到的问题,scrollview 不能正常工作,只能滚动一点,比如我只能滚动到大约 8 或 9 行,下面的其他我不能向下滚动。

    override func viewDidLoad() {
    super.viewDidLoad()
    
    //Step 1
    let scrollview = UIScrollView()
    view.addSubview(scrollview)
    scrollview.translatesAutoresizingMaskIntoConstraints = false
    scrollview.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollview.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    scrollview.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    scrollview.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    scrollview.alwaysBounceVertical = true
    
    //Step 2
    let oneview = UIView()
    scrollview.addSubview(oneview)
    oneview.translatesAutoresizingMaskIntoConstraints = false
    oneview.topAnchor.constraint(equalTo: scrollview.topAnchor).isActive = true
    oneview.bottomAnchor.constraint(equalTo: scrollview.bottomAnchor).isActive = true
    oneview.leadingAnchor.constraint(equalTo: scrollview.leadingAnchor).isActive = true
    oneview.trailingAnchor.constraint(equalTo: scrollview.trailingAnchor).isActive = true
    oneview.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    let heightConstraint = oneview.heightAnchor.constraint(equalTo: view.heightAnchor)
    heightConstraint.isActive = true
    heightConstraint.priority = .defaultLow
    
    //Step 3
    for i in 1...30{
        let field = UITextField()
        field.placeholder = "This is line "+String(i+1)
        field.backgroundColor = .gray
        field.isUserInteractionEnabled = false
        oneview.addSubview(field)
        field.translatesAutoresizingMaskIntoConstraints = false
        field.widthAnchor.constraint(equalTo: oneview.widthAnchor, multiplier: 0.8).isActive = true
        field.heightAnchor.constraint(equalToConstant: 50).isActive = true
        field.centerXAnchor.constraint(equalTo: oneview.centerXAnchor).isActive = true
        field.topAnchor.constraint(equalTo: oneview.topAnchor, constant: CGFloat(100*i)).isActive = true
    }
}

【问题讨论】:

  • 你遇到了什么问题?
  • 对不起,我已经更新了我遇到的上下文问题。谢谢提醒。
  • 您应该为每个文本字段设置顶部锚约束,使其等于前一个文本字段的底部锚约束。并让最后一个文本字段的底部约束等于 oneview 的底部约束。

标签: ios swift xcode


【解决方案1】:

使用这个虚拟子视图(代码中的oneview)的全部意义在于,它的内容可以告诉虚拟子视图它应该是什么高度,并且滚动视图的内容大小适合那个高度。

但是,您的文本字段的约束不建议oneview! 的高度。所有文本字段的约束都说是文本字段

  • 应该在oneview的顶部下方一些距离。
  • 应该有一定的高度
  • 应该与oneview 具有相同的中心 X
  • 应与oneview 具有相同的宽度

为了满足上述条件,oneview 的高度根本不需要改变。布局引擎可以将您的文本字段放在oneview 的范围之外,并且仍然满足上述约束。 (想一想!)

但是,如果您在最后一个文本字段中再添加一个约束,则它

应该在oneview底部上方一定距离

然后oneview 必须调整大小以满足该要求。你是在间接暗示oneview 的高度,因为你在说

对于最后一个文本字段,我希望 this 在其上方有足够的空间,而 this 在其下方有足够的空间。

我们也可以将“特定距离”设为零。以下是您将如何在代码中执行此操作:

// in the loop...
if i == 30 {
    field.bottomAnchor.constraint(equalTo: oneview.bottomAnchor).isActive = true
}

告诉oneview 其高度的更好方法是使用UIStackView。将步骤 2 和 3 替换为:

    let oneview = UIStackView()
    oneview.alignment = .fill
    oneview.distribution = .equalSpacing
    oneview.spacing = 50
    oneview.axis = .vertical
    scrollview.addSubview(oneview)
    oneview.translatesAutoresizingMaskIntoConstraints = false
    oneview.topAnchor.constraint(equalTo: scrollview.topAnchor).isActive = true
    oneview.bottomAnchor.constraint(equalTo: scrollview.bottomAnchor).isActive = true
    oneview.leadingAnchor.constraint(equalTo: scrollview.leadingAnchor).isActive = true
    oneview.trailingAnchor.constraint(equalTo: scrollview.trailingAnchor).isActive = true
    oneview.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    let heightConstraint = oneview.heightAnchor.constraint(equalTo: view.heightAnchor, constant: 25)
    heightConstraint.isActive = true
    heightConstraint.priority = .defaultLow
    
    for i in 1...30{
        let field = UITextField()
        field.placeholder = "This is line "+String(i+1)
        field.backgroundColor = .gray
        field.isUserInteractionEnabled = false
        oneview.addArrangedSubview(field)
        field.translatesAutoresizingMaskIntoConstraints = false
        field.heightAnchor.constraint(equalToConstant: 50).isActive = true
    }

【讨论】:

  • 非常感谢。在考虑了您指出的一些要点后,我明白了它是如何工作的!
【解决方案2】:

问题是第一个顶视图应该锚定到内容视图的顶部,最后一个底视图应该锚定到内容视图的底部

扩展

extension UIScrollView {

func assignKeyboardObservers() {
    
    NotificationCenter.default.addObserver(
        
        self,
        
        selector: #selector(keyboardWillShow),
        
        name: UIResponder.keyboardWillShowNotification,
        
        object: nil
        
    )
    
    NotificationCenter.default.addObserver(
        
        self,
        
        selector: #selector(keyboardWillDissmiss),
        
        name: UIResponder.keyboardWillHideNotification,
        
        object: nil
        
    )
    
}



@objc fileprivate func keyboardWillShow(_ notification: Notification) {
    
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        
        let keyboardRectangle = keyboardFrame.cgRectValue
        
        let keyboardHeight = keyboardRectangle.height
        
        insetScrollView(insetBottom: keyboardHeight)
    }
    
}



@objc fileprivate func keyboardWillDissmiss(_ notification: Notification) {
    
    insetScrollView(insetBottom: 0)
    
}



fileprivate func insetScrollView(insetBottom: CGFloat) {
    
    var inset:UIEdgeInsets = contentInset
    
    inset.bottom = insetBottom
    
    
    
    UIView.animate(withDuration: 0.2, animations: {
        
        self.contentInset = inset
        
    })
    
}

}

extension UIViewController {
func addScrollViewToView(paddingContentView:UIEdgeInsets = .zero, anchorScroll:( _ scrollView: inout UIScrollView)->())->UIView {

    let tapToDismiss = UITapGestureRecognizer(target: self, action: #selector(dimissKeyboard(_:)))
    tapToDismiss.cancelsTouchesInView = false
    view.addGestureRecognizer(tapToDismiss)
    var scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.bounces = true
    scrollView.isScrollEnabled = true
    scrollView.assignKeyboardObservers()
    let contentView = UIView()
    contentView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(scrollView)
    anchorScroll(&scrollView)
    scrollView.addSubview(contentView)
    NSLayoutConstraint.activate([
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: paddingContentView.top),
        contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: paddingContentView.left),
        contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -paddingContentView.right),
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -paddingContentView.bottom),
        contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
        contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
        ])
    return contentView
}

@objc fileprivate func dimissKeyboard(_ sender: UITapGestureRecognizer) {
    view.endEditing(true)
}
}

如何使用它

import UIKit

 class TESTViewController: UIViewController {

private var contentView:UIView!


override func viewDidLoad() {
    super.viewDidLoad()

    contentView = addScrollViewToView(anchorScroll: { (scrollView) in
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
            scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
            scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
        ])
    })
    
    let stackView:UIStackView = UIStackView()
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.axis = .vertical
    stackView.spacing = 3
    stackView.alignment = .fill
    stackView.distribution = .fillEqually
    
    
    for i in 1...30{
        let field = UITextField()
        field.translatesAutoresizingMaskIntoConstraints = false
        field.placeholder = "This is line "+String(i+1)
        field.backgroundColor = .gray
        field.isUserInteractionEnabled = false
        field.heightAnchor.constraint(equalToConstant: 50).isActive = true
        stackView.addSubview(field)
    }
    
    contentView.addSubview(stackView)
    NSLayoutConstraint.activate([
        stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
        stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
        stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
        stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
    ])
}

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    相关资源
    最近更新 更多