覆盖表单大小 - 类

Override Formsheet Size-Classes

有问题的 ViewController 嵌入在 UINavigationController 中并显示为 .FormSheet,如下所示:

class PLViewController:UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.translucent = false
    }

    /// Embeds self into a UINavigationController, adds a "done" button to the navVC and uses the passed ViewController to present self embedded in the NavigationController.
    /// - Parameters:
    ///     - presentingVC: ViewController which will present the formSheet.
    ///     - animated: If TRUE, the presentation of the formsheet will be animated.
    func presentAsFormSheet (presentingVC:UIViewController, animated:Bool, completion:(() -> Void)?) {
        let navVC = UINavigationController(rootViewController: self)
        navVC.modalPresentationStyle = .FormSheet
        let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: Selector("dismissFormSheet"))
        doneButton.tintColor = GlobalVars.cautionColor
        navigationItem.setLeftBarButtonItem(doneButton, animated: false)
        presentingVC.presentViewController(navVC, animated: true, completion: completion)
    }

    /// Dismisses this ViewController with animation from a modal state.
    func dismissFormSheet () {
        dismissViewControllerAnimated(true, completion: nil)
    }

}

当 VC 以 "floating" 表单方式(非全屏模式)呈现时,它的基本行为如下所示:

此外,如果应用程序处于 1/3 分屏(但不是 2/3's)或 iPhone 一般情况下,则需要进一步操作布局。 iPhone 部分很容易理解,基本上检查设备类型并在代码中做出相应响应。

有没有人知道,当开启 iPad 时,a) 在分屏模式下 b) 使用 1/3、1/2 或 2/3?

成功!通过子类化 UIViewController,我能够创建一些方法来以编程方式调整 .FormSheet 模态以响应呈现 VC 的特征变化。

UIViewController子类:

class MyViewControllerSubclass: UIViewController {
private func deviceOrientation () -> UIDeviceOrientation {
        return UIDevice.currentDevice().orientation
    }

    private func getScreenSize () -> (description:String, size:CGRect) {
        let size = UIScreen.mainScreen().bounds
        let str = "SCREEN SIZE:\nwidth: \(size.width)\nheight: \(size.height)"
        return (str, size)
    }

    private func getApplicationSize () -> (description:String, size:CGRect) {
        let size = UIApplication.sharedApplication().windows[0].bounds
        let str = "\n\nAPPLICATION SIZE:\nwidth: \(size.width)\nheight: \(size.height)"
        return (str, size)
    }

    /// Called when the UIViewController's traitCollection has changed.
    /// - Description:
    /// Include any changes that need to be made when the trait collection changes.
    func respondToSizeChange (layoutStyle:LayoutStyle) {

    }


    enum LayoutStyle: String {
        case iPadFullscreen         = "iPad Full Screen"
        case iPadHalfScreen         = "iPad 1/2 Screen"
        case iPadTwoThirdScreen     = "iPad 2/3 Screen"
        case iPadOneThirdScreen     = "iPad 1/3 Screen"
        case iPhoneFullScreen       = "iPhone"
    }

    /// - Returns: a `LayoutStyle` value containing information about what portion of the screen the application is consuming.
    internal func determineLayout () -> LayoutStyle {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return .iPhoneFullScreen
        }
        let screenSize = getScreenSize().size
        let appSize = getApplicationSize().size
        //let orientation = deviceOrientation()
        let screenWidth = screenSize.width
        let appWidth = appSize.width
        if screenSize == appSize {
            return .iPadFullscreen
        }

        if deviceOrientation() == .Portrait && screenSize != appSize {
            return .iPadOneThirdScreen
        }
        // In case the math isn't exact, set a range.
        let lowRange = screenWidth - 15
        let highRange = screenWidth + 15

        if lowRange / 2 <= appWidth && appWidth <= highRange / 2 {
            return .iPadHalfScreen
        } else if appWidth <= highRange / 3 {
            return .iPadOneThirdScreen
        } else {
            return .iPadTwoThirdScreen
        }

    }

    override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        respondToSizeChange(determineLayout())
    }
}

并在ViewController 上显示模态:

class MainViewController:UIViewController {

    /// The modally-presented formSheet.
    var presentedFormSheet:MyViewControllerSubclass?

    /// Modally presents the VC in `.FormSheet` style and sets the local `presentedFormSheet` variable to the VC.
    func showContentRequirementVC() {
        let vc = MyViewControllerSubclass(nibName: "myCustomViewController", bundle: nil)
        vc.modalPresentationStyle = .FormSheet
        presentedFormSheet = vc
        presentViewController(vc, animated: true, completion: nil)
    }

    // When the trait collection changes, tell the presentedFormSheet about it.
    override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
        presentedFormSheet?.respondToSizeChange(determineLayout())
    }
}

结果: 如下面的屏幕截图所示,实心红色条现在仅在表单占用应用程序的整个区域时才会出现。传递的数据中有足够的信息,您也可以分别响应 full、2/3、1/2 和 1/3。模态即使在呈现后也会响应更改。

下面的屏幕截图也证明了这个问题是相关的。如您所见,并排的 table 在我们达到 1/3 或 iPhone 之前效果很好。此时,它们需要位于选项卡栏控制器上或使用其他方法,以便一次只显示一个 table 并且用户可以在它们之间切换。这个特殊的 VC 是用 UIStackViews 构建的,因此可以很容易地以编程方式调整行为以适应 UI 布局。

全屏

** 2/3 屏幕**

1/2 屏幕

1/3 屏幕

侧滑