引子
每个iOS项目里都有少不了『浮层视图』,它们常常用于引导,展示,或与用户交互,并且,点击空白会移除这些视图。
这些浮层视图的实现都很简单,本不值得一提。但我也发现了一个问题,就是大家的实现方式真的五花八门,还有的居然在VC的touchesBegan:withEvent:
里添加移除浮层的代码,代码和VC的耦合十分严重。
所以,我觉得有必要给出一个统一的实现,以达到两个目的:
- 代码复用。
- 减少耦合。
我基于装饰者模式对这种弹出浮层做了一个简单的封装,把项目里的浮层视图都统一了起来。感觉世界一下子清爽了。
实现
项目地址:PopupViewWrapper
具体的实现代码十分的简单,用到了装饰者模式,背景视图KKPopupViewWrapper
和内容视图KKPopupView
都实现了KKPopupViewProtocol
协议。头文件如下:
@protocol KKPopupViewProtocol <NSObject>
- (UIView *)show:(UIView *)parentView;
- (void)hide;
@end
// 给内容视图加一个可点击的背景,点击背景视图隐藏
@interface KKPopupViewWrapper : UIButton <KKPopupViewProtocol>
- (instancetype)initWithView:(id<KKPopupViewProtocol>)popupView;
@property (nonatomic, strong) UIColor * _Nullable bgColor;//默认为nil,表示背景透明
@property (nonatomic, copy) void (^ _Nullable hideHandler) (void);//背景及内容视图消失回调
@end
// 内容视图需继承自该类或创建自该类
@interface KKPopupView : UIView <KKPopupViewProtocol>
@end
源代码就两个文件,大家可以直接把.h和.m文件直接拖进自己的项目。
例子
简单浮层
只需要展示内容的简单浮层,直接创建KKPopupView对象,并在它上面添加内容子视图,然后传给KKPopupViewWrapper
对象显示。
KKPopupView *popupView = [[KKPopupView alloc] initWithFrame:CGRectMake(0, 0, 200, 160)];
popupView.backgroundColor = [UIColor whiteColor];
popupView.center = self.view.center;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 60, 100, 40)];
label.textAlignment = NSTextAlignmentCenter;
label.text = @"Demo 1";
[popupView addSubview:label];
KKPopupViewWrapper *wrapper = [[KKPopupViewWrapper alloc] initWithView:popupView];
// 设置外围背景颜色
wrapper.bgColor = [UIColor colorWithWhite:0 alpha:0.5];
// 处理浮层移除事件
wrapper.hideHandler = ^{
NSLog(@"Popup View is removed.");
};
[wrapper show:self.view];
背景视图可以设置背景色,默认是透明的;还可以通过hideHandler
处理浮层移除事件。
复杂浮层
复杂一些或有交互的浮层,可以继承自KKPopupView。
// 继承自KKPopupView的浮层
@interface DemoPopupView : KKPopupView
@end
DemoPopupView *popupView = [[DemoPopupView alloc] initWithFrame:CGRectMake(0, 0, 200, 180)];
popupView.backgroundColor = [UIColor whiteColor];
popupView.center = self.view.center;
KKPopupViewWrapper *wrapper = [[KKPopupViewWrapper alloc] initWithView:popupView];
wrapper.bgColor = [UIColor colorWithWhite:0 alpha:0.5];
[wrapper show:self.view];
弹出和移除动画
有弹出和移除动画的浮层,动画代码需要添加在重写的show和hide方法里。
@interface DemoPopupView2 : KKPopupView
@end
@implementation DemoPopupView2
#pragma mark - override
- (UIView *)show:(UIView *)parentView
{
[parentView addSubview:self];
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.frame;
frame.origin.y = parentView.frame.size.height - frame.size.height;
self.frame = frame;
}];
return self;
}
- (void)hide
{
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.frame;
frame.origin.y = self.superview.frame.size.height;
self.frame = frame;
} completion:^(BOOL finished) {
[super hide];
}];
}
@end
总结
从调用的代码我们可以看出,用户只需要创建wrapper对象和popup内容视图对象,并调用显示方法即可。移除浮层的代码被封装了起来,自动执行。这样就达到了减少和调用端代码耦合以及复用的目的。