MZFormSheetPresentationController 2.4.3

MZFormSheetPresentationController 2.4.3

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
Released最后发布2017年9月

Michal Zaborowski 维护。



  • 作者:
  • Miłosz Zaborowski

MZFormSheetPresentationController 为原生 iOS UIModalPresentationFormSheet 提供了替代方案,增加了对 iPhone 的支持并提供了设置控制器尺寸和形式弹窗的更多机会。

MZFormSheetPresentationController 还定义了多种预定义的动画,您可以根据需要自定义模态表单是滑入、淡入、弹入还是创建自定义动画。还有许多属性可用于自定义表单的精确外观和位置。它还支持滑动手势取消。

该项目是 MZFormSheetController 的延续,允许您在部署目标设置为 >iOS5 时使用形式弹窗,但使用了某些巧妙的 UIWindow 拦截方法。

以下是几幅展示 MZFormSheetPresentationController 的图像




2.x 更新日志

  • 经过全面测试并通过认证,支持 iOS 9
  • 支持 tvOS
  • 修复了基于大小类的文本尺寸问题
  • 修复了自动布局问题
  • 添加了每个方向的取消手势
  • 重写了 MZFormSheetPresentationController 以使用 UIPresentationController
  • 支持为内容视图添加阴影
  • 添加了框架配置处理程序,允许您在旋转和动画期间更改框架
  • 添加了 shouldCenterHorizontally 属性
  • 允许自定义动画器以支持原生过渡
  • 允许使动态内容视图大小依赖于显示的 UIViewController

从 1.x 升级

由于作为主要版本变更,2.0 版本中引入的 API 与 1.x 集成不向后兼容。升级很简单。

  • 使用 MZFormSheetPresentationViewController 而不是 MZFormSheetPresentationController

  • MZFormSheetPresentationController 现在继承自 UIPresentationController 并管理弹出窗口的显示

  • MZFormSheetPresentationViewController 包含属性 presentationController,允许您自定义显示的内容视图

  • MZFormSheetPresentationController registerTransitionClass 现在是 MZTransition registerTransitionClass

  • 函数 func entryFormSheetControllerTransition(formSheetController: MZFormSheetPresentationController, completionHandler: MZTransitionCompletionHandler) 已更改为 func entryFormSheetControllerTransition(formSheetController: UIViewController, completionHandler: MZTransitionCompletionHandler),其中 formSheetController 框架等于 contentViewSize 并具有视图原点。

要求

MZFormSheetPresentationController 需要 iOS 8.x 或更高版本。

安装

###Carthage

在您的 Cartfile 中添加以下行。

github "m1entus/MZFormSheetPresentationController" "master"

然后运行 carthage update --no-use-binaries 或只需 carthage update

在构建框架之后,您需要将其添加到您的项目中,并使用框架头文件导入它。

#import "<MZFormSheetPresentationController/MZFormSheetPresentationControllerFramework.h>"

有关Carthage的安装和使用细节,请访问其项目页面。

###CocoaPods

将以下行添加到您的 Podfile 中。

# Uncomment this line to define a global platform for your project
platform :ios, '8.0'
# Uncomment this line if you're using Swift
use_frameworks!

target 'ProjectName' do
    pod 'MZFormSheetPresentationController'
end

然后运行 pod install --verbose 或只需 pod install。有关CocoaPods的安装和使用详情,请访问其项目页面

如何使用

有两个示例项目,一个是Objective-C的,另一个是Swift的。

让我们从一个简单的例子开始

Objective-C

UINavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:@"formSheetController"];
MZFormSheetPresentationViewController *formSheetController = [[MZFormSheetPresentationViewController alloc] initWithContentViewController:navigationController];
formSheetController.presentationController.contentViewSize = CGSizeMake(250, 250); // or pass in UILayoutFittingCompressedSize to size automatically with auto-layout

[self presentViewController:formSheetController animated:YES completion:nil];

Swift

let navigationController = self.storyboard!.instantiateViewControllerWithIdentifier("formSheetController") as! UINavigationController
let formSheetController = MZFormSheetPresentationViewController(contentViewController: navigationController)
formSheetController.presentationController?.contentViewSize = CGSizeMake(250, 250)  // or pass in UILayoutFittingCompressedSize to size automatically with auto-layout

self.presentViewController(formSheetController, animated: true, completion: nil)

这将在表单页面容器内显示视图控制器。

如果您想关闭表单页面控制器,请使用默认的关闭视图控制器动作。

Objective-C

[self dismissViewControllerAnimated:YES completion:nil];

Swift

self.dismissViewControllerAnimated(true, completion: nil)

很简单,对吧 ?!

传递数据

如果您想将数据传递给显示视图控制器,您会像平常一样做。记住,IBOutlets在viewDidLoad之后初始化,如果您不想创建额外的属性,您始终可以使用完成块 willPresentContentViewControllerHandler 直接将数据传递到 outlets。它是在viewWillAppear之后和在 MZFormSheetPresentationViewController 动画之前调用的。

Objective-C

MZFormSheetPresentationViewController *formSheetController = [[MZFormSheetPresentationViewController alloc] initWithContentViewController:navigationController];

PresentedTableViewController *presentedViewController = [navigationController.viewControllers firstObject];
presentedViewController.textFieldBecomeFirstResponder = YES;
presentedViewController.passingString = @"PASSSED DATA!!";

formSheetController.willPresentContentViewControllerHandler = ^(UIViewController *vc) {
    UINavigationController *navigationController = (id)vc;
    PresentedTableViewController *presentedViewController = [navigationController.viewControllers firstObject];
    [presentedViewController.view layoutIfNeeded];
    presentedViewController.textField.text = @"PASS DATA DIRECTLY TO OUTLET!!";
};

[self presentViewController:formSheetController animated:YES completion:nil];

Swift

let formSheetController = MZFormSheetPresentationViewController(contentViewController: navigationController)

let presentedViewController = navigationController.viewControllers.first as! PresentedTableViewController
presentedViewController.textFieldBecomeFirstResponder = true
presentedViewController.passingString = "PASSED DATA"

formSheetController.willPresentContentViewControllerHandler = { vc in
    let navigationController = vc as! UINavigationController
    let presentedViewController = navigationController.viewControllers.first as! PresentedTableViewController
    presentedViewController.view?.layoutIfNeeded()
    presentedViewController.textField?.text = "PASS DATA DIRECTLY TO OUTLET!!"
}

self.presentViewController(formSheetController, animated: true, completion: nil)

使用滑动手势关闭

typedef NS_OPTIONS(NSUInteger, MZFormSheetPanGestureDismissDirection) {
    MZFormSheetPanGestureDismissDirectionNone = 0,
    MZFormSheetPanGestureDismissDirectionUp = 1 << 0,
    MZFormSheetPanGestureDismissDirectionDown = 1 << 1,
    MZFormSheetPanGestureDismissDirectionLeft = 1 << 2,
    MZFormSheetPanGestureDismissDirectionRight = 1 << 3,
    MZFormSheetPanGestureDismissDirectionAll = MZFormSheetPanGestureDismissDirectionUp | MZFormSheetPanGestureDismissDirectionDown | MZFormSheetPanGestureDismissDirectionLeft | MZFormSheetPanGestureDismissDirectionRight
};
UINavigationController *navigationController = [self formSheetControllerWithNavigationController];
MZFormSheetPresentationViewController *formSheetController = [[MZFormSheetPresentationViewController alloc] initWithContentViewController:navigationController];

formSheetController.interactivePanGestureDissmisalDirection = MZFormSheetPanGestureDismissDirectionAll;

[self presentViewController:formSheetController animated:YES completion:nil];

模糊背景效果

您可以显示模糊背景,您可以将 MZFormSheetPresentationController 默认外观设置为模糊,或者直接将其设置为 MZFormSheetPresentationController

Objective-C

// Blur will be applied to all MZFormSheetPresentationControllers by default
[[MZFormSheetPresentationController appearance] setShouldApplyBackgroundBlurEffect:YES];

or

// This will set to only one instance
formSheetController.shouldApplyBackgroundBlurEffect = YES;

Swift

// Blur will be applied to all MZFormSheetPresentationControllers by default
MZFormSheetPresentationController.appearance().shouldApplyBackgroundBlurEffect = true

or

// This will set to only one instance
formSheetController.shouldApplyBackgroundBlurEffect = true

转场效果

MZFormSheetPresentationViewController有自己的预定义转场。

Objective-C

typedef NS_ENUM(NSInteger, MZFormSheetPresentationTransitionStyle) {
 MZFormSheetPresentationTransitionStyleSlideFromTop = 0,
 MZFormSheetPresentationTransitionStyleSlideFromBottom,
 MZFormSheetPresentationTransitionStyleSlideFromLeft,
 MZFormSheetPresentationTransitionStyleSlideFromRight,
 MZFormSheetPresentationTransitionStyleSlideAndBounceFromTop,
 MZFormSheetPresentationTransitionStyleSlideAndBounceFromBottom,
 MZFormSheetPresentationTransitionStyleSlideAndBounceFromLeft,
 MZFormSheetPresentationTransitionStyleSlideAndBounceFromRight,
 MZFormSheetPresentationTransitionStyleFade,
 MZFormSheetPresentationTransitionStyleBounce,
 MZFormSheetPresentationTransitionStyleDropDown,
 MZFormSheetPresentationTransitionStyleCustom,
 MZFormSheetPresentationTransitionStyleNone,
};

如果您想使用它们,您只需分配 contentViewControllerTransitionStyle 属性即可。

Objective-C

formSheetController.contentViewControllerTransitionStyle = MZFormSheetPresentationTransitionStyleFade;

您也可以通过实现 MZFormSheetPresentationViewControllerTransitionProtocol 协议并注册您自己的转场类作为自定义样式来创建自己的转场。

Objective-C

@interface CustomTransition : NSObject <MZFormSheetPresentationViewControllerTransitionProtocol>
@end

[MZTransition registerTransitionClass:[CustomTransition class] forTransitionStyle:MZFormSheetTransitionStyleCustom];

formSheetController.contentViewControllerTransitionStyle = MZFormSheetTransitionStyleCustom;

Swift

class CustomTransition: NSObject, MZFormSheetPresentationViewControllerTransitionProtocol {
}

MZTransition.registerTransitionClass(CustomTransition.self, forTransitionStyle: .Custom)

formSheetController.contentViewControllerTransitionStyle = .Custom

如果您正在创建自己的转场,您必须在动画结束时调用 completionBlock。

Objective-C

- (void)exitFormSheetControllerTransition:(nonnull UIViewController *)presentingViewController
                        completionHandler:(nonnull MZTransitionCompletionHandler)completionHandler {
    CGRect formSheetRect = presentingViewController.view.frame;
    formSheetRect.origin.x = [UIScreen mainScreen].bounds.size.width;

    [UIView animateWithDuration:0.3
                          delay:0
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{
                         presentingViewController.view.frame = formSheetRect;
                     }
                     completion:^(BOOL finished) {
                         completionHandler();
                     }];
}

Swift

func exitFormSheetControllerTransition(presentingViewController: UIViewController, completionHandler: MZTransitionCompletionHandler) {
    var formSheetRect = presentingViewController.view.frame
    formSheetRect.origin.x = UIScreen.mainScreen().bounds.size.width

    UIView.animateWithDuration(0.3, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
        presentingViewController.view.frame = formSheetRect
    }, completion: {(value: Bool)  -> Void in
        completionHandler()
    })
}

透明触摸背景

如果您想访问位于 MZFormSheetPresentationController 之下的控制器,您可以设置属性 transparentTouchEnabled,背景视图控制器将获得所有触摸。

Objective-C

MZFormSheetPresentationViewController *formSheetController = [[MZFormSheetPresentationViewController alloc] initWithContentViewController:viewController];
formSheetController.presentationController.transparentTouchEnabled = YES;

Swift

let formSheetController = MZFormSheetPresentationViewController(contentViewController: viewController)
formSheetController.presentationController?.transparentTouchEnabled = true

完成块

/**
 The handler to call when presented form sheet is before entry transition and its view will show on window.
 */
@property (nonatomic, copy, nullable) MZFormSheetPresentationViewControllerCompletionHandler willPresentContentViewControllerHandler;

/**
 The handler to call when presented form sheet is after entry transition animation.
 */
@property (nonatomic, copy, nullable) MZFormSheetPresentationViewControllerCompletionHandler didPresentContentViewControllerHandler;

/**
 The handler to call when presented form sheet will be dismiss, this is called before out transition animation.
 */
@property (nonatomic, copy, nullable) MZFormSheetPresentationViewControllerCompletionHandler willDismissContentViewControllerHandler;

/**
 The handler to call when presented form sheet is after dismiss.
 */
@property (nonatomic, copy, nullable) MZFormSheetPresentationViewControllerCompletionHandler didDismissContentViewControllerHandler;

自动布局

MZFormSheetPresentationController支持自动布局。

Storyboard

MZFormSheetPresentationController支持Storyboard。

MZFormSheetPresentationViewControllerSegue 是一个自定义Storyboard转场,它使用默认的MZFormSheetPresentationController设置。

如果您想通过Storyboard转场访问表单页面控制器并传递数据,代码将如下所示

Objective-C

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"segue"]) {
        MZFormSheetPresentationControllerSegue *presentationSegue = (id)segue;
        presentationSegue.formSheetPresentationController.presentationController.shouldApplyBackgroundBlurEffect = YES;
        UINavigationController *navigationController = (id)presentationSegue.formSheetPresentationController.contentViewController;
        PresentedTableViewController *presentedViewController = [navigationController.viewControllers firstObject];
        presentedViewController.textFieldBecomeFirstResponder = YES;
        presentedViewController.passingString = @"PASSSED DATA!!";
    }
}

Swift

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let identifier = segue.identifier {
        if identifier == "segue" {
            let presentationSegue = segue as! MZFormSheetPresentationViewControllerSegue
            presentationSegue.formSheetPresentationController.presentationController?.shouldApplyBackgroundBlurEffect = true
            let navigationController = presentationSegue.formSheetPresentationController.contentViewController as! UINavigationController
            let presentedViewController = navigationController.viewControllers.first as! PresentedTableViewController
            presentedViewController.textFieldBecomeFirstResponder = true
            presentedViewController.passingString = "PASSED DATA"
        }
    }
}

ARC

MZFormSheetPresentationController使用ARC。

应用扩展

某些位置计算访问 [UIApplication sharedApplication],这在应用扩展中是不允许的。如果您想在扩展中使用 MZFormSheetPresentationController,请在相应的目标中添加预处理器宏 MZ_APP_EXTENSIONS=1。

如果您使用Cocoapods,您可以使用post install钩子来完成此操作。

post_install do |installer|
    installer.pods_project.targets.each do |target|
        if target.name == "MZFormSheetPresentationController"
            target.build_configurations.each do |config|
                config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
                config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'MZ_APP_EXTENSIONS=1'
            end
        end
    end
end

联系方式

Michal Zaborowski

Twitter