【问题标题】:How do I convert UIPageViewController content to UIScrollView?如何将 UIPageViewController 内容转换为 UIScrollView?
【发布时间】:2020-01-30 23:45:36
【问题描述】:

我目前有一个应用程序的入门部分,其中一个 UIPageViewController 中有六个 ViewController。由于 UIPageViewController 的限制,我想改为使用 UIScrollView,这样我就可以充分利用分页以及 UIScrollView 委托方法。

视图都是使用 Storyboard 构建的,所以我需要弄清楚如何将它们带入启用分页的 UIScrollView。我找到的所有参考资料都显示了如何以编程方式在 UIScrollView 中创建视图,如下所示:

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!

    @IBOutlet weak var pageControl: UIPageControl!

    let colors = [UIColor.cyan, UIColor.blue, UIColor.green, UIColor.yellow]
    var frame = CGRect(x: 0, y: 0 , width: 0, height: 0)

    override func viewDidLoad() {
        super.viewDidLoad()

        for index in 0..<colors.count {
            frame.origin.x = scrollView.frame.size.width * CGFloat(index)
            frame.size = scrollView.frame.size

            let subView = UIView(frame: frame)
            subView.backgroundColor = colors[index]
            scrollView.addSubview(subView)
        }

        scrollView.contentSize = CGSize(width: scrollView.frame.size.width * CGFloat(colors.count), height: scrollView.frame.size.height)

    }
}

如何将 Storyboards 中创建的视图引入 UIScrollView?

运行 Xcode 11。

【问题讨论】:

  • 首先,使用自动布局约束而不是明确的帧大小。其次,将视图控制器加载为子视图控制器,并将它们的视图添加到滚动视图中。
  • @DonMag 您的简洁性有其优点,但更多细节对于仍然严重依赖教程来学习绳索的人会非常有帮助。

标签: ios xcode uiscrollview


【解决方案1】:

让您开始...

基本思路是:

  • 使用UIScrollViewUIPageControl 创建您的“主”视图控制器
    • 正常排列和约束它们
  • 在滚动视图中添加UIStackView
    • 将顶部/前导/尾随/底部(全部为零)约束到滚动视图的内容布局指南
    • 将堆栈视图的高度限制为等于滚动视图的框架布局指南高度
    • 约束堆栈视图的宽度等于滚动视图的框架布局指南宽度,优先级为 250(因此我们可以水平扩展它)
  • 照常创建“页面”视图控制器(如果您使用的是UIPageViewController,则可以使用相同的 VC)

在您的代码中,您将:

  • 使用storyboard?.instantiateViewController(withIdentifier: "storyboard id") 实例化每个“页面”视图控制器
  • 将每个 VC 的视图添加到堆栈视图中
  • 将每个 VC 视图的高度和宽度约束设置为等于滚动视图的高度和宽度
  • 将每个 VC 添加为子视图控制器

这里是示例代码:

//
//  ScrollChildrenViewController.swift
//
//  Created by Don Mag on 10/2/19.
//

import UIKit

class FirstViewController: UIViewController {
}

class SecondViewController: UIViewController {
}

class ThirdViewController: UIViewController {
}

class ScrollChildrenViewController: UIViewController, UIScrollViewDelegate {

    @IBOutlet var scrollView: UIScrollView!
    @IBOutlet var stackView: UIStackView!
    @IBOutlet var pageControl: UIPageControl!

    override func viewDidLoad() {
        super.viewDidLoad()

        if let firstVC  = storyboard?.instantiateViewController(withIdentifier: "FirstVC"),
            let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondVC"),
            let thirdVC  = storyboard?.instantiateViewController(withIdentifier: "ThirdVC") {

            [firstVC, secondVC, thirdVC].forEach {
                vc in
                vc.view.translatesAutoresizingMaskIntoConstraints = false
                stackView.addArrangedSubview(vc.view)
                NSLayoutConstraint.activate([
                    vc.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
                    vc.view.heightAnchor.constraint(equalTo: scrollView.frameLayoutGuide.heightAnchor),
                ])
                self.addChild(vc)
                vc.didMove(toParent: self)
            }

        }

        pageControl.numberOfPages = stackView.arrangedSubviews.count

        scrollView.delegate = self

    }

    @IBAction func changePage(_ sender: Any) {
        let x = CGFloat(pageControl.currentPage) * scrollView.frame.size.width
        scrollView.setContentOffset(CGPoint(x:x, y:0), animated: true)
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let pageNumber = round(scrollView.contentOffset.x / scrollView.frame.size.width)
        pageControl.currentPage = Int(pageNumber)
    }

}

导致:

这是我使用的 Storyboard 的来源(与上述代码的 IB 连接和 Storyboard ID 匹配):

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="HA6-Hm-gNO">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Scroll Children View Controller-->
        <scene sceneID="FeD-sX-zkf">
            <objects>
                <viewController id="HA6-Hm-gNO" customClass="ScrollChildrenViewController" customModule="X11SwiftScratch" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="guw-AN-V6Z">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AJV-iC-aAl">
                                <rect key="frame" x="20" y="20" width="335" height="570"/>
                                <subviews>
                                    <stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aG7-ac-pRi">
                                        <rect key="frame" x="0.0" y="0.0" width="335" height="570"/>
                                    </stackView>
                                </subviews>
                                <constraints>
                                    <constraint firstItem="aG7-ac-pRi" firstAttribute="leading" secondItem="AJV-iC-aAl" secondAttribute="leading" id="3Nf-2e-Lvd"/>
                                    <constraint firstItem="aG7-ac-pRi" firstAttribute="width" secondItem="QBH-AA-ldV" secondAttribute="width" priority="250" id="73U-dy-cDC"/>
                                    <constraint firstAttribute="bottom" secondItem="aG7-ac-pRi" secondAttribute="bottom" id="c4T-p7-smf"/>
                                    <constraint firstAttribute="trailing" secondItem="aG7-ac-pRi" secondAttribute="trailing" id="fcJ-yI-Rhr"/>
                                    <constraint firstItem="aG7-ac-pRi" firstAttribute="height" secondItem="QBH-AA-ldV" secondAttribute="height" id="lev-mF-lqF"/>
                                    <constraint firstItem="aG7-ac-pRi" firstAttribute="top" secondItem="QBH-AA-ldV" secondAttribute="top" id="r17-FW-2AS"/>
                                </constraints>
                                <viewLayoutGuide key="contentLayoutGuide" id="y7N-I3-1Zo"/>
                                <viewLayoutGuide key="frameLayoutGuide" id="QBH-AA-ldV"/>
                            </scrollView>
                            <pageControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="wbc-5i-RSa">
                                <rect key="frame" x="40" y="610" width="295" height="37"/>
                                <color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                <constraints>
                                    <constraint firstAttribute="height" constant="37" id="Mnd-Q4-F8P"/>
                                </constraints>
                                <connections>
                                    <action selector="changePage:" destination="HA6-Hm-gNO" eventType="valueChanged" id="fjQ-Wa-gcL"/>
                                </connections>
                            </pageControl>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemYellowColor" red="1" green="0.80000000000000004" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="wbc-5i-RSa" firstAttribute="top" secondItem="AJV-iC-aAl" secondAttribute="bottom" constant="20" id="7Ry-XJ-xei"/>
                            <constraint firstItem="vZA-Us-fWZ" firstAttribute="bottom" secondItem="wbc-5i-RSa" secondAttribute="bottom" constant="20" id="M1u-ay-zwW"/>
                            <constraint firstItem="vZA-Us-fWZ" firstAttribute="trailing" secondItem="AJV-iC-aAl" secondAttribute="trailing" constant="20" id="TFB-sw-TS8"/>
                            <constraint firstItem="vZA-Us-fWZ" firstAttribute="trailing" secondItem="wbc-5i-RSa" secondAttribute="trailing" constant="40" id="Z9x-TT-Qp2"/>
                            <constraint firstItem="AJV-iC-aAl" firstAttribute="top" secondItem="vZA-Us-fWZ" secondAttribute="top" constant="20" id="h6y-ZT-gOJ"/>
                            <constraint firstItem="AJV-iC-aAl" firstAttribute="leading" secondItem="vZA-Us-fWZ" secondAttribute="leading" constant="20" id="hsS-4R-mJN"/>
                            <constraint firstItem="wbc-5i-RSa" firstAttribute="leading" secondItem="vZA-Us-fWZ" secondAttribute="leading" constant="40" id="pnQ-HO-wog"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="vZA-Us-fWZ"/>
                    </view>
                    <connections>
                        <outlet property="pageControl" destination="wbc-5i-RSa" id="Jp4-bx-MON"/>
                        <outlet property="scrollView" destination="AJV-iC-aAl" id="gRc-d1-ovk"/>
                        <outlet property="stackView" destination="aG7-ac-pRi" id="A7K-p6-0qb"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="IcG-Qh-9Bs" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="97" y="101"/>
        </scene>
        <!--First View Controller-->
        <scene sceneID="6lF-tN-5dp">
            <objects>
                <viewController storyboardIdentifier="FirstVC" id="UGA-X4-xWu" customClass="FirstViewController" customModule="X11SwiftScratch" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Cbg-Bf-5of">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="First" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QpL-Cz-Cyz">
                                <rect key="frame" x="75" y="167" width="225" height="333.5"/>
                                <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <fontDescription key="fontDescription" type="system" pointSize="34"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="QpL-Cz-Cyz" firstAttribute="centerY" secondItem="Cbg-Bf-5of" secondAttribute="centerY" id="KfQ-r8-wAh"/>
                            <constraint firstItem="QpL-Cz-Cyz" firstAttribute="height" secondItem="Z13-Ky-FK3" secondAttribute="height" multiplier="0.5" id="LcM-2k-rx2"/>
                            <constraint firstItem="QpL-Cz-Cyz" firstAttribute="centerX" secondItem="Cbg-Bf-5of" secondAttribute="centerX" id="Yrm-dS-0f5"/>
                            <constraint firstItem="QpL-Cz-Cyz" firstAttribute="width" secondItem="Z13-Ky-FK3" secondAttribute="width" multiplier="0.6" id="ZZA-ZB-a0f"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="Z13-Ky-FK3"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="B2Z-Uu-lBa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="751" y="100"/>
        </scene>
        <!--Second View Controller-->
        <scene sceneID="GUP-16-paa">
            <objects>
                <viewController storyboardIdentifier="SecondVC" id="Zqm-Ha-81P" customClass="SecondViewController" customModule="X11SwiftScratch" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="F6j-rn-0IC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Second" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LNi-xp-nA8">
                                <rect key="frame" x="75" y="167" width="225" height="333.5"/>
                                <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <fontDescription key="fontDescription" type="system" pointSize="34"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemGreenColor" red="0.20392156859999999" green="0.78039215689999997" blue="0.34901960780000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="LNi-xp-nA8" firstAttribute="centerY" secondItem="F6j-rn-0IC" secondAttribute="centerY" id="6tP-P6-OWb"/>
                            <constraint firstItem="LNi-xp-nA8" firstAttribute="width" secondItem="scO-8f-hyo" secondAttribute="width" multiplier="0.6" id="AFz-Rh-Uqp"/>
                            <constraint firstItem="LNi-xp-nA8" firstAttribute="height" secondItem="scO-8f-hyo" secondAttribute="height" multiplier="0.5" id="Kb2-i6-5cq"/>
                            <constraint firstItem="LNi-xp-nA8" firstAttribute="centerX" secondItem="F6j-rn-0IC" secondAttribute="centerX" id="Vhi-Ml-T71"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="scO-8f-hyo"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="oOe-A7-SKt" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1399" y="99"/>
        </scene>
        <!--Third View Controller-->
        <scene sceneID="IRH-Pv-biB">
            <objects>
                <viewController storyboardIdentifier="ThirdVC" id="moo-RP-Ao6" customClass="ThirdViewController" customModule="X11SwiftScratch" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="29I-Jb-Oxe">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Third" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bqa-p6-6PN">
                                <rect key="frame" x="75" y="167" width="225" height="333.5"/>
                                <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <fontDescription key="fontDescription" type="system" pointSize="34"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <color key="backgroundColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstItem="bqa-p6-6PN" firstAttribute="height" secondItem="uvx-3l-6lL" secondAttribute="height" multiplier="0.5" id="3wA-wk-XA4"/>
                            <constraint firstItem="bqa-p6-6PN" firstAttribute="centerX" secondItem="29I-Jb-Oxe" secondAttribute="centerX" id="4ie-qL-hRk"/>
                            <constraint firstItem="bqa-p6-6PN" firstAttribute="width" secondItem="uvx-3l-6lL" secondAttribute="width" multiplier="0.6" id="7fh-8L-PGY"/>
                            <constraint firstItem="bqa-p6-6PN" firstAttribute="centerY" secondItem="29I-Jb-Oxe" secondAttribute="centerY" id="O3M-zi-oGO"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="uvx-3l-6lL"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="GGY-3Y-kct" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="2062" y="99"/>
        </scene>
    </scenes>
</document>

注意:

值得指出...虽然这有效地复制了UIPageViewController 的行为,但您已经失去了所有内置的内存管理。

如果你只有几个“页面”,没什么大不了的......但如果你有大量的“页面”,我想你应该权衡一下你从这种方法中获得的任何好处(相对于@ 987654331@).

【讨论】:

  • 如果我负责珍珠之门,我会因为这篇文章让你进入天堂。非常感谢您花时间做这件事。对此,我真的非常感激。我一直在工作和寻找几天来试图解决这个问题。你是最棒的。
  • 快速跟进。如何为 scrollView 内的 UIViewContollers 设置 scrollView.delegate = self?我试图在每个视图中触发动画,但无法设置委托。有什么想法吗?
  • 一个滚动视图只能有一个委托......您可能想要做的是将“主”VC设置为委托,然后将滚动事件传递给孩子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多