【问题标题】:How to make horizontal UIScrollView with dynamic width?如何制作具有动态宽度的水平 UIScrollView?
【发布时间】:2021-11-23 15:30:12
【问题描述】:

我有一个动态增加宽度的标签。 我决定将它添加到 ScrollView(以便用户可以在标签中看到任意长度的文本)。

但是我遇到了一个问题。实现这一点的正确方法是什么?我要怎么做。如何制作动态宽度的水平滚动视图?

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        scrollView.contentSize = .init(width: label.frame.width, height: label.frame.height)
    }
    
    func setupScrollView() {
        view.addSubview(scrollView)
        scrollView.addSubview(label)
        
        let frameLayoutGuide = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([
            frameLayoutGuide.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 400),
            frameLayoutGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 100),
            frameLayoutGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -100),
            frameLayoutGuide.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -300),
        ])
        
        let contentLayoutGuide = scrollView.contentLayoutGuide
        
        NSLayoutConstraint.activate([
            contentLayoutGuide.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 400),
            contentLayoutGuide.centerXAnchor.constraint(equalTo: frameLayoutGuide.centerXAnchor),
            contentLayoutGuide.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -300),

            label.centerXAnchor.constraint(equalTo: contentLayoutGuide.centerXAnchor),
            label.centerYAnchor.constraint(equalTo: contentLayoutGuide.centerYAnchor)
        ])
    }

【问题讨论】:

    标签: uiscrollview uikit


    【解决方案1】:

    抱歉,您对scrollView.contentLayoutGuidescrollView.frameLayoutGuide 的使用非常错误。

    您希望将scrollView 本身约束到其父视图(在本例中为主view)并将滚动视图的子视图 约束到滚动视图的.contentLayoutGuide。然后,您可以使用 scrollView 的 .frameLayoutGuide 来帮助设置其子视图的大小。

    因此,如果您希望标签在滚动视图中居中,但在标签太宽而无法容纳时启用水平滚动,您希望:

    • 将标签添加到“持有人”视图中,并限制在中心
    • 将该“持有人”视图添加到滚动视图
      • 将其位置限制在.contentLayoutGuide
      • 将其大小限制为.frameLayoutGuide
    • 为标签添加前导和尾随约束以强制“持有人”视图在需要时增长

    这是一个简单的例子。它将在标签的不同长度字符串之间循环...滚动将根据标签的最终宽度自动启用或禁用(所有这些都具有自动布局 - 无需计算大小):

    class ViewController: UIViewController {
        
        let scrollView = UIScrollView()
        let label = UILabel()
        let labelHolderView = UIView()
    
        let sampleStrings: [String] = [
            "Short (no scrolling).",
            "A little longer (still no scrolling).",
            "A much longer string, that will definitely require horizontal scrolling.",
            "Just for kicks, let's make this string really, really long, to help demonstrate the benefits of using auto-layout!",
        ]
        
        var stringIndex: Int = 0
        
        override func viewDidLoad() {
            super.viewDidLoad()
            setupScrollView()
        }
        
        func setupScrollView() {
            
            // add the label to the holder view
            labelHolderView.addSubview(label)
            
            // add the holder view to the scroll view
            scrollView.addSubview(labelHolderView)
            
            // add the scroll view to the view
            view.addSubview(scrollView)
    
            // all three need this
            labelHolderView.translatesAutoresizingMaskIntoConstraints = false
            label.translatesAutoresizingMaskIntoConstraints = false
            scrollView.translatesAutoresizingMaskIntoConstraints = false
    
            let safeG = view.safeAreaLayoutGuide
            let contentG = scrollView.contentLayoutGuide
            let frameG = scrollView.frameLayoutGuide
            
            NSLayoutConstraint.activate([
                
                // let's put a 100-pt tall scroll view
                //  40-pts from the bottom
                //  40-pts on each side
                scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -40.0),
                scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 40.0),
                scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -40.0),
                scrollView.heightAnchor.constraint(equalToConstant: 100.0),
    
                // constrain holder view to ContentGuide with Zero on all 4 sides
                labelHolderView.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 0.0),
                labelHolderView.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 0.0),
                labelHolderView.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: 0.0),
                labelHolderView.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: 0.0),
    
                // we only want horizontal scrolling, so constrain
                //  holder view height to sccroll view FrameGuide
                labelHolderView.heightAnchor.constraint(equalTo: frameG.heightAnchor),
                
                // we want the label centered horizontally
                //  in the holder view and in the scroll view
                //  so set holder view width >= FrameGuide
                labelHolderView.widthAnchor.constraint(greaterThanOrEqualTo: frameG.widthAnchor, constant: 0.0),
                
                // center the label in the holder view
                label.centerXAnchor.constraint(equalTo: labelHolderView.centerXAnchor),
                label.centerYAnchor.constraint(equalTo: labelHolderView.centerYAnchor),
                
                // as the label expands horizontally, we want at least
                //  8-pts on each side
                label.leadingAnchor.constraint(greaterThanOrEqualTo: labelHolderView.leadingAnchor, constant: 8.0),
                label.trailingAnchor.constraint(lessThanOrEqualTo: labelHolderView.trailingAnchor, constant: -8.0),
                
            ])
            
            // let's use some background colors so we can see the view frames
            scrollView.backgroundColor = .yellow
            labelHolderView.backgroundColor = .systemTeal
            label.backgroundColor = .green
            
            // add a button above the scroll view to cycle through our sample strings
            let b = UIButton()
            b.setTitle("Tap Me", for: [])
            b.setTitleColor(.white, for: .normal)
            b.setTitleColor(.lightGray, for: .highlighted)
            b.backgroundColor = .systemGreen
            b.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(b)
            NSLayoutConstraint.activate([
                b.bottomAnchor.constraint(equalTo: scrollView.topAnchor, constant: -20.0),
                b.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 0.6),
                b.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
            ])
            
            b.addTarget(self, action: #selector(gotTap(_:)), for: .touchUpInside)
            
            // set the initial text
            gotTap(nil)
            
        }
    
        @objc func gotTap(_ sender: Any?) -> Void {
            label.text = sampleStrings[stringIndex % sampleStrings.count]
            stringIndex += 1
        }
        
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-21
      • 2021-02-11
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多