【问题标题】:Embedded UIPageController child VC has wrong frame origin嵌入式 UIPageController 子 VC 的帧来源错误
【发布时间】:2020-09-07 17:59:49
【问题描述】:

我正在尝试在页面中间创建一个如下所示的布局元素并利用UIPageViewController 来完成它。

我在容器视图中嵌入了UIPageViewController。卡片元素的内容有一个由 AutoLayout 确定的高度,并且向边缘水平拉伸,卡片有一个最大宽度,之后它保持居中。但是我遇到了一个奇怪的问题。当我将卡片元素的 VC 设置为我的 UIPageViewController 的内容时,单个页面的大小大部分都正确,但它的原点超出了 pageVC 的内容视图的范围。

我在一个非常小的测试项目中重现了这个问题。这是情节提要和相关限制:

这是我的代码:

class ViewController: UIViewController {

    var pageController: UIPageViewController!

    override func viewDidLoad() {
        super.viewDidLoad()
        guard let vc = storyboard?.instantiateViewController(withIdentifier: "PageView") else { return }
        pageController.setViewControllers([vc], direction: .forward, animated: true, completion: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let dest = segue.destination as? UIPageViewController {
            pageController = dest
        }
    }

}

class SinglePageViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.translatesAutoresizingMaskIntoConstraints = false
    }

}

这是我实际得到的:

我尝试在SinglePageViewController 中设置view.autoresizingMask = [.flexibleWidth, .flexibleLeftMargin, .flexibleRightMargin] 而不是view.translatesAutoresizingMaskIntoConstraints = false,这样可以提供正确的前导、尾随和宽度约束,但是我无法让UIView-Encapsulated-Layout-Height: self.height = 0 约束消失。没有系统约束可以解释原点错位,所以我不知道如何进一步调试。层次结构中较高的所有视图的高度都为 0,并且所有较低的视图都正确放置。如果我将SinglePageViewController 直接嵌入到容器视图中,它的布局非常完美,但如果我将UIPageViewController 放在两者之间,它就会中断。

为什么UIPageViewController 不限制其中的页面以匹配其视图的边界?有什么办法可以让它工作吗?

【问题讨论】:

    标签: ios uipageviewcontroller ios-autolayout uicontainerview


    【解决方案1】:

    首先,你不应该这样做:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // don't do this
        //view.translatesAutoresizingMaskIntoConstraints = false
    
    }
    

    当从 Storyboard 实例化视图时,它们会加载适当的大小调整掩码...视图控制器的“根”视图 需要 translatesAutoresizingMaskIntoConstraints 设置为 @987654332 @ 以使布局正常工作。

    删除那条线可能会让你到达你需要的地方,但我认为你有几个约束设置不正确。

    这是我设置的故事板的外观:

    然后,使用以下代码:

    //
    //  EmbeddedPageViewViewController.swift
    //  Created by Don Mag on 5/21/20.
    //
    
    import UIKit
    
    class EmbeddedPageViewViewController: UIViewController {
    
        var pageController: UIPageViewController!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            guard let vc = storyboard?.instantiateViewController(withIdentifier: "PageView") else { return }
            pageController.setViewControllers([vc], direction: .forward, animated: true, completion: nil)
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if let dest = segue.destination as? UIPageViewController {
                pageController = dest
            }
        }
    
    }
    
    class SinglePageViewController: UIViewController {
    
        @IBOutlet var bkgView: UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            bkgView.backgroundColor = .white
            bkgView.layer.cornerRadius = 8.0
            bkgView.layer.shadowColor = UIColor.black.cgColor
            bkgView.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
            bkgView.layer.shadowRadius = 2.0
            bkgView.layer.shadowOpacity = 0.35
    
        }
    
    }
    

    我得到这个结果:

    主视图的背景颜色设置为“cantaloupe”,以便于看到UIContainerView的框架。

    旋转到横向:

    宽度最大为 325 并保持居中。

    作为参考,以下是未将视图背景设置为白色时的外观:

    这是我的故事板的来源:

    <?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="hya-IX-JpL">
        <device id="retina4_7" 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>
            <!--Embedded Page View View Controller-->
            <scene sceneID="TRC-Gf-9JR">
                <objects>
                    <viewController id="hya-IX-JpL" customClass="EmbeddedPageViewViewController" customModule="PassBackNavController" customModuleProvider="target" sceneMemberID="viewController">
                        <view key="view" contentMode="scaleToFill" id="gkJ-Gz-CPw">
                            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <subviews>
                                <containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IRh-01-Go2">
                                    <rect key="frame" x="8" y="270" width="359" height="128"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="128" id="GT3-zg-F9u"/>
                                    </constraints>
                                    <connections>
                                        <segue destination="tRW-tL-JaM" kind="embed" id="DRB-mh-M2m"/>
                                    </connections>
                                </containerView>
                            </subviews>
                            <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <constraints>
                                <constraint firstItem="IRh-01-Go2" firstAttribute="leading" secondItem="qBw-JJ-Fx5" secondAttribute="leading" constant="8" id="Aqh-1J-Wli"/>
                                <constraint firstItem="IRh-01-Go2" firstAttribute="centerY" secondItem="gkJ-Gz-CPw" secondAttribute="centerY" id="NLG-5N-8Lb"/>
                                <constraint firstItem="qBw-JJ-Fx5" firstAttribute="trailing" secondItem="IRh-01-Go2" secondAttribute="trailing" constant="8" id="oDL-2p-roM"/>
                            </constraints>
                            <viewLayoutGuide key="safeArea" id="qBw-JJ-Fx5"/>
                        </view>
                    </viewController>
                    <placeholder placeholderIdentifier="IBFirstResponder" id="dnU-Gs-r2b" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
                </objects>
                <point key="canvasLocation" x="119" y="131"/>
            </scene>
            <!--Single Page View Controller-->
            <scene sceneID="L0K-o3-YNb">
                <objects>
                    <viewController storyboardIdentifier="PageView" id="cfk-9g-Gkj" customClass="SinglePageViewController" customModule="PassBackNavController" customModuleProvider="target" sceneMemberID="viewController">
                        <view key="view" contentMode="scaleToFill" id="7CL-c5-Z9a">
                            <rect key="frame" x="0.0" y="0.0" width="375" height="200"/>
                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                            <subviews>
                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nC5-Ym-QUo">
                                    <rect key="frame" x="25" y="12" width="325" height="176"/>
                                    <subviews>
                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="umo-Tg-dpR">
                                            <rect key="frame" x="20" y="78" width="285" height="20.5"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                            <nil key="textColor"/>
                                            <nil key="highlightedColor"/>
                                        </label>
                                    </subviews>
                                    <color key="backgroundColor" red="0.075549371539999993" green="0.79593962429999998" blue="0.99987417460000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <constraints>
                                        <constraint firstItem="umo-Tg-dpR" firstAttribute="leading" secondItem="nC5-Ym-QUo" secondAttribute="leading" constant="20" id="HXw-12-L1h"/>
                                        <constraint firstAttribute="width" priority="750" constant="325" id="Tfm-wt-KFB"/>
                                        <constraint firstAttribute="trailing" secondItem="umo-Tg-dpR" secondAttribute="trailing" constant="20" id="by3-Y5-AqR"/>
                                        <constraint firstItem="umo-Tg-dpR" firstAttribute="centerY" secondItem="nC5-Ym-QUo" secondAttribute="centerY" id="fIW-R2-QXc"/>
                                    </constraints>
                                </view>
                            </subviews>
                            <color key="backgroundColor" red="0.97619122270000003" green="0.97633117439999995" blue="0.97616070509999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                            <constraints>
                                <constraint firstItem="nC5-Ym-QUo" firstAttribute="top" secondItem="7CL-c5-Z9a" secondAttribute="top" constant="12" id="ASL-q5-MnJ"/>
                                <constraint firstItem="nC5-Ym-QUo" firstAttribute="centerX" secondItem="7CL-c5-Z9a" secondAttribute="centerX" id="O2h-f7-lBG"/>
                                <constraint firstItem="nC5-Ym-QUo" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="7CL-c5-Z9a" secondAttribute="leading" constant="16" id="RWx-xc-AnB"/>
                                <constraint firstAttribute="bottom" secondItem="nC5-Ym-QUo" secondAttribute="bottom" constant="12" id="gJ0-QG-ApQ"/>
                                <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="nC5-Ym-QUo" secondAttribute="trailing" constant="16" id="mEx-VN-uJ4"/>
                            </constraints>
                            <viewLayoutGuide key="safeArea" id="QrT-IP-grh"/>
                        </view>
                        <size key="freeformSize" width="375" height="200"/>
                        <connections>
                            <outlet property="bkgView" destination="nC5-Ym-QUo" id="dx9-da-bUg"/>
                        </connections>
                    </viewController>
                    <placeholder placeholderIdentifier="IBFirstResponder" id="Lfo-H7-oVB" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
                </objects>
                <point key="canvasLocation" x="884" y="275"/>
            </scene>
            <!--Page View Controller-->
            <scene sceneID="jMx-mM-wG7">
                <objects>
                    <pageViewController autoresizesArchivedViewToFullSize="NO" transitionStyle="pageCurl" navigationOrientation="horizontal" spineLocation="min" id="tRW-tL-JaM" sceneMemberID="viewController"/>
                    <placeholder placeholderIdentifier="IBFirstResponder" id="xla-ir-fR9" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
                </objects>
                <point key="canvasLocation" x="897" y="38"/>
            </scene>
        </scenes>
    </document>
    

    【讨论】:

    • 这对我来说不太适用,因为卡片内部的内容应该决定高度。我不想将容器视图限制为恒定高度,它应该随内容垂直调整大小。这就是我玩translatesAutoresizingMaskIntoConstraints的原因。
    • @NewShelbyWoo - 好的,使用UIPageViewController 很难做到这一点。您的每个“页面”是否(可能)具有不同的高度?所以你希望容器视图的高度随着你从一个页面移动到另一个页面而改变?
    • 一个页面控制器中的每个页面不会有不同的高度,但是我将这个组件重用于不同类型的内容,因此页面下方的相同元素将具有不同的高度
    • @NewShelbyWoo - 你知道设计时“页面浏览量”的高度吗?还是在运行时才知道它们?
    • @NewShelbyWoo - 看看这个项目中的“示例 3”:github.com/DonMag/AutosizeContainer ... 看看这是否是你想要做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    相关资源
    最近更新 更多