对外只暴露了KGModal这一个类,实际上在KGModal.m这个实现文件中,另外还实现了KGModalViewController,KGModalContainerView,KGModalGradientView,KGModalCloseButton这几个未暴露在KGModal接口中的”私有”类。
KGModalCloseButton
自定义的按钮,通过代码绘制了一张关闭的图片赋给button的background image。
KGModalGradientView
模态视图的背景遮罩层,根据KGModal单例的backgroundDisplayStyle绘制。并复写了- touchesEnded:withEvent:方法,当该方法触发时发送KGModalGradientViewTapped通知,用于实现点击遮罩层是否使模态框消失。
KGModalContainerView
模态框内容view的容器view,可通过KGModal的modalBackgroundColor设置容器view的背景色。KGModalContainerView创建了一个styleLayer用于展示边框、圆角、阴影等效果并添加到view的layer中,设置背景色实质上是设置的styleLayer的背景色。
KGModalViewController
整个模态框的显示是通过添加到一个新创建的window上实现的,KGModalViewController实例将作为新window对象的rootViewController,作为除contentView外其他界面元素的控制器。初始化时,首先实例化一个KGModalGradientView添加到该viewController的view中作为背景遮罩层。控制器中有关是否随界面旋转的复写方法返回KGModal单例的shouldRotate的值。
KGModal
维持强引用:
window(UIWindow
)
contentViewController(UIViewController
)
弱引用:
viewController(KGModalViewController
)
containerView(KGModalContainerView
)
closeButton(KGModalCloseButton
)
contentView(UIView
)
有一个共享单例的类方法,复写init方法设置了接口属性
shouldRotate
、
tapOutsideToDismiss
、
animateWhenDismissed
、
closeButtonType
、
modalBackgroundColor
的默认值。
有四个show方法:
- showWithContentView:
- showWithContentViewController:
- showWithContentViewController:andAnimated:
- showWithContentView:andAnimated:
最终实现是在- showWithContentView:andAnimated:
方法中,其他show方法调用该方法,如果参数是viewController,则会在方法中用属性contentViewController维持引用,再调用showContentView方法传入contentController的view。
- showWithContentView:andAnimated:
的实现是先初始化一个UIWindow对象赋值给self.window,然后初始化一个KGModalViewController对象作为window对象的rootViewController,并赋值给self.viewController。接着初始化KGModalContainerView,将contentView放入其中,添加到KGModalViewController对象的view上,布局到中间位置。
初始化KGModalCloseButton,根据closeButtonType布局,并绑定隐藏模态框的方法,监听KGModalGradientViewTapped通知,并绑定响应方法,根据tapOutsideToDismiss决定是否隐藏。最后,使window对象显示出来并发送相应的生命周期通知,根据参数决定是否动画显示。window显示的代码通过GCD强制在主线程运行。
四个hide方法:
- hide
- hideWithCompletionBlock:
- hideAnimated:
- hideAnimated:withCompletionBlock:
最终实现是在- hideAnimated:withCompletionBlock:
方法中,其他hide方法调用该方法,主要调用cleanup方法,包括取消对通知的监听,置空对contentViewController的引用,window的引用。然后发送相应的生命周期通知,根据参数决定是否动画隐藏。隐藏的代码通过GCD强制在主线程运行。
PS.
- KGModal的show方法会每次重新创建新的window实例赋给其window属性,所以如果是在一个模态框中弹出另一个的场景就会出现问题,如果两次弹出模态框都使用的是共享单例的话,那么当第二个模态框弹出时,第一个模态框所在的window已经没有引用维护了。可新建一个KGModal的实例用于此场景。
- KGModal每次新建的window对象使用默认的level,这样如果在modal view中有textfield使用放大镜效果时,放大镜会显示主window的内容,而不是modal view所在window的内容。具体原因还不清楚,提高modal view所在的window的level不会有这个问题。