【问题标题】:Vertical ScrollView not scrolling (No Storyboard)垂直 ScrollView 不滚动(无情节提要)
【发布时间】:2020-11-22 08:59:26
【问题描述】:

我需要帮助创建不带情节提要的滚动视图。这是我设置滚动视图的代码;我没有设置滚动视图的 contentSize,因为我希望滚动视图内容大小是动态的,取决于 TextView 中的文本量。我所做的是尝试将“contentView”添加到 Scroll View 并将我的所有 UI 元素添加到 contentView。任何帮助将不胜感激。

import Foundation
import UIKit
import UITextView_Placeholder

class ComposerVC: UIViewController {
  
  private var scrollView: UIScrollView = {
    let scrollView = UIScrollView(frame: UIScreen.main.bounds)
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    return scrollView
  }()
  
  private var contentView: UIView = {
    let content = UIView()
    content.translatesAutoresizingMaskIntoConstraints = false
    return content
  }()
  
  private var title: UITextView = {
    let title = UITextView()
    title.translatesAutoresizingMaskIntoConstraints = false
    title.placeholder = "Untitled"
    title.textColor = UIColor(hexString: "#50E3C2")
    title.font = UIFont(name: "Rubik-BoldItalic", size: 32)
    title.backgroundColor = .clear
    title.isScrollEnabled = false
    return title
  }()
  
  private var divider: UIView = {
    let divider = UIView()
    divider.translatesAutoresizingMaskIntoConstraints = false
    divider.backgroundColor = UIColor(hexString: "#50E3C2")
    return divider
  }()
  
  private var content: UITextView = {
    let title = UITextView()
    title.translatesAutoresizingMaskIntoConstraints = false
    title.placeholder = "Begin writing here..."
    title.textColor = .white
    title.font = UIFont(name: "Avenir-Book", size: 15)
    title.backgroundColor = .clear
    title.isScrollEnabled = false
    return title
  }()
  
  override func viewDidLoad() {
    setupUI()
    setupUIConstraints()
    title.delegate = self
  }
  
  private func setupUI() {
    view.backgroundColor = UIColor(hexString: "#131415")
    view.addSubview(scrollView)
    scrollView.addSubview(contentView)
    contentView.addSubview(title)
    contentView.addSubview(divider)
    contentView.addSubview(content)
  }
  
  private func setupUIConstraints() {
    
    scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    
    contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
    contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
    contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
    contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
    contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    
    title.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 95).isActive = true
    title.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 35).isActive = true
    title.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -35).isActive = true
    
    divider.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 15).isActive = true
    divider.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
    divider.heightAnchor.constraint(equalToConstant: 1).isActive = true
    divider.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.8).isActive = true
    
    content.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 15).isActive = true
    content.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 35).isActive = true
    content.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -35).isActive = true
  }
}

extension ComposerVC: UITextViewDelegate {
  func textViewDidChange(_ textView: UITextView) {
    let fixedWidth = textView.frame.size.width
    let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
  }
}

【问题讨论】:

    标签: ios swift uiscrollview


    【解决方案1】:

    几个提示:

    1. 不要对变量使用现有名称...按原样使用您的代码,private var title: UITextView 会导致问题(title 已经是视图控制器属性)。
    2. 使用暗示对象的 var 名称...例如titleTextViewcontentTextView 而不是 titlecontent
    3. 在开发期间 - 特别是在您处理布局时 - 为您的 UI 元素提供对比背景色,以便您可以在运行时轻松查看它们的框架。
    4. 使用代码创建的视图时,设置.clipsToBounds = true ...如果您没有看到您添加的任何子视图,您就知道框架/约束缺少一些东西。

    我没有你的 UITextView_Placeholder 导入,但这不应该影响这里的任何东西......

    所以,首先,将您的 viewDidLoad() 更改为:

    override func viewDidLoad() {
        setupUI()
        setupUIConstraints()
        titleTextView.delegate = self
        
        // contrasting colors during development
        scrollView.backgroundColor = .red
        titleTextView.backgroundColor = .yellow
        contentTextView.backgroundColor = .green
        divider.backgroundColor = .blue
        contentView.backgroundColor = .cyan
    }
    

    当你运行它时,你应该会看到(滚动视图背景是红色的,这是没有占位符的东西):

    看起来正确,除了没有青色的contentView

    现在,剪辑contentView的子视图:

    private var contentView: UIView = {
        let content = UIView()
        content.translatesAutoresizingMaskIntoConstraints = false
        // add this line
        content.clipsToBounds = true
        return content
    }()
    

    结果:

    一切都去哪儿了?好吧,我们没有看到青色contentView,现在我们看不到它的任何子视图 ...如果我们使用Debug View Hierarchy,我们可以发现contentView的高度为零。

    通过限制setupUIConstraints() 中第二个文本视图的底部来解决此问题(我已将其重命名为contentTextView 而不仅仅是content):

        contentTextView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -95).isActive = true
    

    我们得到:

    现在青色contentView 的高度由其子视图的正确设置约束控制。

    附带说明:正确设置约束,并为文本视图禁用滚动,您不需要您的:

    extension ComposerVC: UITextViewDelegate {
      //func textViewDidChange(_ textView: UITextView) {
      //...
      //}
    }
    

    文本视图会根据其文本自动调整大小:

    这是完整的编辑代码:

    class ComposerVC: UIViewController {
        
        private var scrollView: UIScrollView = {
            let scrollView = UIScrollView(frame: UIScreen.main.bounds)
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            return scrollView
        }()
        
        private var contentView: UIView = {
            let content = UIView()
            content.translatesAutoresizingMaskIntoConstraints = false
            // add this line so we know if the constraints are set correctly
            content.clipsToBounds = true
            return content
        }()
        
        private var titleTextView: UITextView = {
            let title = UITextView()
            title.translatesAutoresizingMaskIntoConstraints = false
    //      title.placeholder = "Untitled"
            title.textColor = UIColor(hexString: "#50E3C2")
            title.font = UIFont(name: "Rubik-BoldItalic", size: 32)
            title.backgroundColor = .clear
            title.isScrollEnabled = false
            return title
        }()
        
        private var divider: UIView = {
            let divider = UIView()
            divider.translatesAutoresizingMaskIntoConstraints = false
            divider.backgroundColor = UIColor(hexString: "#50E3C2")
            return divider
        }()
        
        private var contentTextView: UITextView = {
            let title = UITextView()
            title.translatesAutoresizingMaskIntoConstraints = false
    //      title.placeholder = "Begin writing here..."
            title.textColor = .white
            title.font = UIFont(name: "Avenir-Book", size: 15)
            title.backgroundColor = .clear
            title.isScrollEnabled = false
            return title
        }()
        
        override func viewDidLoad() {
            setupUI()
            setupUIConstraints()
            titleTextView.delegate = self
            
            // contrasting colors during development
            scrollView.backgroundColor = .red
            titleTextView.backgroundColor = .yellow
            contentTextView.backgroundColor = .green
            divider.backgroundColor = .blue
            contentView.backgroundColor = .cyan
        }
        
        private func setupUI() {
            view.backgroundColor = UIColor(hexString: "#131415")
            view.addSubview(scrollView)
            scrollView.addSubview(contentView)
            contentView.addSubview(titleTextView)
            contentView.addSubview(divider)
            contentView.addSubview(contentTextView)
        }
        
        private func setupUIConstraints() {
            
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
            
            contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
            contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
            contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
            contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
            contentView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
            
            titleTextView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 95).isActive = true
            titleTextView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 35).isActive = true
            titleTextView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -35).isActive = true
            
            divider.topAnchor.constraint(equalTo: titleTextView.bottomAnchor, constant: 15).isActive = true
            divider.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
            divider.heightAnchor.constraint(equalToConstant: 1).isActive = true
            divider.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.8).isActive = true
            
            contentTextView.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 15).isActive = true
            contentTextView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 35).isActive = true
            contentTextView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -35).isActive = true
            
            contentTextView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -95).isActive = true
        
        }
    }
    
    extension ComposerVC: UITextViewDelegate {
    //  func textViewDidChange(_ textView: UITextView) {
    //      let fixedWidth = textView.frame.size.width
    //      let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
    //      textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
    //  }
    }
    

    【讨论】:

      【解决方案2】:

      假设您使用的是 iOS 11+,您的 contentView 应该将其锚点约束到 scrollView 的 contentLayoutGuide。像这样:

      contentView
          .leadingAnchor
          .constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor).isActive = true
      contentView
          .topAnchor
          .constraint(equalTo: scrollView.contentLayoutGuide.topAnchor).isActive = true
      contentView
          .trailingAnchor
          .constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor).isActive = true
      contentView
          .bottomAnchor
          .constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor).isActive = true
      

      另外,它的宽度应该被限制在 scrollView 的 frameLayoutGuide 而不是视图的宽度,像这样:

      contentView
      .widthAnchor
      .constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor).isActive = true
      

      这应该让 scrollView 检测到适合的内容大小。

      【讨论】:

        猜你喜欢
        • 2018-05-24
        • 1970-01-01
        • 1970-01-01
        • 2020-09-23
        • 1970-01-01
        • 1970-01-01
        • 2022-01-11
        • 1970-01-01
        • 2012-09-22
        相关资源
        最近更新 更多