首页 > 解决方案 > 包含堆栈视图(和/或内容视图)的滚动视图无法按预期工作

问题描述

我想要一个滚动视图,在堆栈视图中垂直显示我的所有东西。

  1. contentView首先,我在包含堆栈视图的滚动视图中创建了一个名为的视图,这意味着我现在有了view-> scrollView-> contentView-> stackView
  2. 我将内容视图的前导、尾随、顶部和底部锚点设置为等于滚动视图内容布局指南的那些约束。
  3. 我使内容视图的宽度与滚动视图框架布局指南的宽度相同。
  4. 我使堆栈视图的前导、尾随、顶部和底部锚点等于内容视图的相应锚点。

在此处输入图像描述

这不会滚动。

我尝试遵循这个 SO答案

  1. 我摆脱了Content Layout Guides并将contentView的约束应用于所有 4 个边,并将其水平和垂直居中到滚动视图。
  2. 在尺寸检查器中,将底部和对齐中心 Y 优先级更改为 250。
  3. 将堆栈视图的底部锚点设置为view(而不是滚动视图)。

在此处输入图像描述

这只会滚动一点,但不会完全滚动底部。大部分视图只是隐藏在屏幕之外。

我还尝试将contentView所有内容一起删除并将我的堆栈视图固定到滚动视图或view直接固定,但没有一个有效。

最后,我尝试了这个超级 hacky-looking 解决方案:

override func viewWillLayoutSubviews(){
    super.viewWillLayoutSubviews()
    scrollView.contentSize = CGSize(width: view.bounds.width, height: view.bounds.height+300)
}

但是,它会垂直挤压堆栈视图并且不会完全显示内容。

PS我正在以编程方式添加堆栈视图的约束:

stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true

标签: iosswiftuiscrollviewautolayoutuistackview

解决方案


这是一个可行的例子——看看你是否能弄清楚你可能做了什么不同的事情。

我们将直接通过代码将堆栈视图添加到滚动视图,而不是使用“内容视图”。

这是故事板布局:

在此处输入图像描述

这是 Storyboard 的源代码,因此您可以直接检查它:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dVO-AO-rAX">
    <device id="retina3_5" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Kevvv View Controller-->
        <scene sceneID="e7x-2X-Pdg">
            <objects>
                <viewController id="dVO-AO-rAX" customClass="KevvvViewController" customModule="MiniScratch" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="ZMq-2S-yNo">
                        <rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bEj-BB-5lU">
                                <rect key="frame" x="0.0" y="44" width="320" height="402"/>
                                <viewLayoutGuide key="contentLayoutGuide" id="VmC-Gj-CCr"/>
                                <viewLayoutGuide key="frameLayoutGuide" id="HBJ-Ua-m26"/>
                            </scrollView>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <constraints>
                            <constraint firstItem="bEj-BB-5lU" firstAttribute="leading" secondItem="goZ-oS-cQl" secondAttribute="leading" id="Jwq-Tg-wRK"/>
                            <constraint firstItem="goZ-oS-cQl" firstAttribute="bottom" secondItem="bEj-BB-5lU" secondAttribute="bottom" constant="34" id="bHJ-DL-1xi"/>
                            <constraint firstItem="bEj-BB-5lU" firstAttribute="trailing" secondItem="goZ-oS-cQl" secondAttribute="trailing" id="gIL-OY-ENf"/>
                            <constraint firstItem="bEj-BB-5lU" firstAttribute="top" secondItem="goZ-oS-cQl" secondAttribute="top" constant="44" id="zAh-qk-82E"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="goZ-oS-cQl"/>
                    </view>
                    <connections>
                        <outlet property="scrollView" destination="bEj-BB-5lU" id="jYI-Wh-d6w"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="ieG-NN-t0K" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="136.875" y="105"/>
        </scene>
    </scenes>
</document>

下面是示例代码,它将向滚动视图添加堆栈视图,向堆栈视图添加 40 个标签,然后将堆栈视图正确约束到滚动视图:

class KevvvViewController: UIViewController {

    @IBOutlet var scrollView: UIScrollView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 12
        
        stack.translatesAutoresizingMaskIntoConstraints = false
        
        scrollView.addSubview(stack)
        
        for i in 1...40 {
            let v = UILabel()
            v.backgroundColor = .yellow
            v.text = "Label \(i)"
            stack.addArrangedSubview(v)
        }

        NSLayoutConstraint.activate([
            stack.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
            stack.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
            stack.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
            stack.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
            
            stack.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
        ])
        
        // to make it easy to see the scroll view frame
        scrollView.backgroundColor = .cyan
    }
    
}

结果,向下滚动到第 17 个标签(iPhone 8)后:

在此处输入图像描述


推荐阅读