由于项目中经常会有一些需求页面是,从底部弹出一个视图,在当前视图的上面,因此为了减少那些没必要的工作量,基于UIPresentationController写了一个工具类,效果图如下:
使用工具说明:
代码实现如下:
ViewController.m文件
#import "ViewController.h"
#import "TTPresentationObject.h"
#import "BViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
//点击弹出
- (IBAction)alerAction:(UIButton *)sender {
CGFloat windowW = [UIScreen mainScreen].bounds.size.width;
TTPresentationObject *object =[TTPresentationObject
sharedTTPresentationObject];
object.subViewFrame=CGRectMake(0, 0, windowW, 100);//控制底部视图位置,如果不传
就使用内部定义的默认值
[object showPresentingViewController:self PresentedViewController:[[BViewCon
troller alloc] init]];
}
@end
BViewController.m文件
#import "BViewController.h"
@interface BViewController ()
@end
@implementation BViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor=[UIColor redColor];
}
@end
TTCustomPresentationVc.h
#import <UIKit/UIKit.h>
@class TTPresentationObject;
@interface TTCustomPresentationVc : UIPresentationController
@property (nonatomic, strong)UIVisualEffectView *visualView;
@end
TTCustomPresentationVc.m
#import "TTCustomPresentationVc.h"
#import "TTPresentationObject.h"
@implementation TTCustomPresentationVc
//presentationTransitionWillBegin 是在呈现过渡即将开始的时候被调用的。我们在这个方
法中把半透明黑色背景 View 加入到 containerView 中,并且做一个 alpha 从0到1的渐变
过渡动画。
- (void) presentationTransitionWillBegin
{
//使用UIVisualEffectView实现模糊效果
UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
_visualView = [[UIVisualEffectView alloc]initWithEffect:blur];
_visualView.frame = self.containerView.bounds;
_visualView.alpha = 0.3;
_visualView.backgroundColor = [UIColor blackColor];
[_visualView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTar
get:self action:@selector(dismissController)]];
[self.containerView addSubview:_visualView];
}
-(void)dismissController{
[self.presentingViewController dismissViewControllerAnimated:YES completion:
nil];
}
//presentationTransitionDidEnd: 是在呈现过渡结束时被调用的,并且该方法提供一个布尔
变量来判断过渡效果是否完成。在我们的例子中,我们可以使用它在过渡效果已结束但没有完成时
移除半透明的黑色背景 View。
-(void)presentationTransitionDidEnd:(BOOL)completed {
// 如果呈现没有完成,那就移除背景 View
if (!completed) {
[_visualView removeFromSuperview];
}
}
//以上就涵盖了我们的背景 View 的呈现部分,我们现在需要给它添加淡出动画并且在它消失后
移除它。正如你预料的那样,dismissalTransitionWillBegin 正是我们把它的 alpha 重新设
回0的地方。
-(void)dismissalTransitionWillBegin {
_visualView.alpha = 0.0;
}
//我们还需要在消失完成后移除背景 View。做法与上面 presentationTransitionDidEnd: 类
似,我们重载 dismissalTransitionDidEnd: 方法
-(void)dismissalTransitionDidEnd:(BOOL)completed{
if (completed) {
[_visualView removeFromSuperview];
}
}
//还有最后一个方法需要重载。在我们的自定义呈现中,被呈现的 view 并没有完全完全填充整
个屏幕,而是很小的一个矩形。被呈现的 view 的过渡动画之后的最终位置,是由
UIPresentationViewController 来负责定义的。我们重载
frameOfPresentedViewInContainerView 方法来定义这个最终位置
- (CGRect)frameOfPresentedViewInContainerView
{
CGFloat windowH = [UIScreen mainScreen].bounds.size.height;
CGFloat windowW = [UIScreen mainScreen].bounds.size.width;
// self.presentedView.frame = CGRectMake(0, windowH - 260, windowW, 260);
self.presentedView.frame = [TTPresentationObject sharedTTPresentationObject].s
ubViewFrame;
if ([NSStringFromCGRect(self.presentedView.frame) isEqualToString:
NSStringFromCGRect(CGRectZero)]) {
self.presentedView.frame = CGRectMake(0, windowH - 260, windowW, 260);
}
return self.presentedView.frame;
}
@end
TTPresentationObject.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "TTSingleton.h"
@class TTCustomPresentationVc;
//该类是一个用来页面底部弹出一个弹框的单例需要传入一个跳转前和跳转后的控制器
@interface TTPresentationObject : NSObject
TTSingletonH(TTPresentationObject);
/**弹框视图位置 在调用下面方法之前一定要先给这个赋值*/
@property (nonatomic)CGRect subViewFrame;
/**
弹出视图
@param presentingViewController 跳转前的原控制器
@param presentedViewController 将要跳转到的目标控制器
*/
-(void)showPresentingViewController:(UIViewController *)presentingViewControll
er PresentedViewController:(UIViewController *)presentedViewController;
TTPresentationObject.m
#import "TTPresentationObject.h"
#import "TTCustomPresentationVc.h"
@interface TTPresentationObject ()<UIViewControllerTransitioningDelegate>
@end
@implementation TTPresentationObject
TTSingletonM(TTPresentationObject);
/**
弹出视图
@param presentingViewController 跳转前的原控制器
@param presentedViewController 将要跳转到的目标控制器
*/
-(void)showPresentingViewController:(UIViewController *)presentingViewControll
erPresentedViewController(UIViewController*)presentedViewController{
// 设置 动画样式
presentedViewController.modalPresentationStyle = UIModalPresentationCustom;
// 此对象要实现 UIViewControllerTransitioningDelegate 协议
presentedViewController.transitioningDelegate = self;
[presentingViewController.navigationController presentViewController:presen
tedViewController animated:YES completion:nil];
}
#pragma mark - UIViewControllerTransitioningDelegate
// 返回控制控制器弹出动画的对象
/**
* 参数: presentedViewController 将要跳转到的目标控制器
presentingViewController 跳转前的原控制器
*/
- (UIPresentationController *)presentationControllerForPresentedViewController:
(UIViewController *)presented presentingViewController:(UIViewController *)pre
senting sourceViewController:(UIViewController *)source{
return [[TTCustomPresentationVc alloc] initWithPresentedViewController:pre
sented presentingViewController:presenting];
}
TTSingleton.h 单例宏
#define TTSingletonH(name) + (instancetype)shared##name;
#if __has_feature(objc_arc)
#define TTSingletonM(name) \
static id _instatice;\
\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instatice=[super allocWithZone:zone];\
});\
return _instatice;\
}\
+ (instancetype)shared##name\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instatice=[[self alloc]init];\
});\
return _instatice;\
}\
-(id)copyWithZone:(NSZone *)zone{return _instatice;}
#else
#define TTSingletonM(name) \
static id _instatice;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instatice=[super allocWithZone:zone];\
});\
return _instatice;\
}\
+ (instancetype)shared##name\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instatice=[[self alloc]init];\
});\
return _instatice;\
}\
-(id)copyWithZone:(NSZone *)zone{return _instatice;}\
-(oneway void)release{}\
-(instancetype)retain{return self;}\
-(NSUInteger)retainCount{return 1;}\
-(instancetype)autorelease{return self;}
#endif
底部视图布局写在BViewController中就可以,相关的事件处理,都可以独立处理;以上只是对UIPresentationController使用的一种封装,后面会陆续上传相关的其他使用方案的封装,敬请关注,谢谢!