MMPopupView 源碼分析
MMPopupView 是什么
MMPopupView 是一個基于UIWindow的一個簡潔、高效的彈出框組件,其中包括 :MMAlertView & MMSheetView 這兩種內置的展示效果,另外開發者也可以自定義彈出視圖以及相關事務;
typedef NS_ENUM(NSUInteger, MMPopupType) {
MMPopupTypeAlert,
MMPopupTypeSheet,
MMPopupTypeCustom,
};
來源
MMPopupView 適用場景
MMPopupView 可適用于照片選擇、時間選擇、性別選擇彈出框以及提示、警告、以及自定義彈出框的搭建;
MMPopupView 工作邏輯
-
層次結構
- MMPopupView 是基于 UIWindow 展現彈出框的基類的,但與相對直接基于當前 UIWindow 來說,它用 MMPopupWindow 這個UIWindow 單例來顯示或隱藏所有彈出框的容器,并處理相關的手勢事件;
- MMPopupView 通過 維護和管理 MMPopupItem 結構數組 來管理包括 高亮、顏色、是否可用、標題、block等單元屬性;
- MMPopupView 使用自己的 Category 來完成最后的 視圖填充、視圖動畫、視圖約束、背景顏色、UIWindow 隱藏和展示等;
@property (nonatomic, strong, readonly ) UIView *mm_dimBackgroundView;
@property (nonatomic, assign, readonly ) BOOL mm_dimBackgroundAnimating;
@property (nonatomic, assign ) NSTimeInterval mm_dimAnimationDuration;
@property (nonatomic, strong, readonly ) UIView *mm_dimBackgroundBlurView;
@property (nonatomic, assign ) BOOL mm_dimBackgroundBlurEnabled;
@property (nonatomic, assign ) UIBlurEffectStyle mm_dimBackgroundBlurEffectStyle;
- (void) mm_showDimBackground;
(void) mm_hideDimBackground;
(void) mm_distributeSpacingHorizontallyWith:(NSArray*)view;
- (void) mm_distributeSpacingVerticallyWith:(NSArray*)view;</code></pre>
MMPopupView 實現細節
-
MMPopupWindow的定義如下:
@interface MMPopupWindow : UIWindow
@property (nonatomic, assign) BOOL touchWildToHide; // default is NO. When YES, popup views will be hidden when user touch the translucent background.
@property (nonatomic, readonly) UIView* attachView;
- (MMPopupWindow *)sharedWindow;
/**
- cache the window to prevent the lag of the first showing.
*/
- (void) cacheWindow;
@end</code></pre>
很簡單 只有一個屬性 touchWildToHide 用來控制是否可以點擊非彈出框的地方來使彈出框消失 還有一個 cacheWindow 的方法來預加載 MMPopupWindow 防止第一次使用的時候頓卡;
-
MMPopupWindow 定義如下:
typedef NS_ENUM(NSUInteger, MMPopupType) {
MMPopupTypeAlert,
MMPopupTypeSheet,
MMPopupTypeCustom,
};
@class MMPopupView;
typedef void(^MMPopupBlock)(MMPopupView );
typedef void(^MMPopupCompletionBlock)(MMPopupView , BOOL);
@interface MMPopupView : UIView
@property (nonatomic, assign, readonly) BOOL visible; // default is NO.
@property (nonatomic, strong ) UIView *attachedView; // default is MMPopupWindow. You can attach MMPopupView to any UIView.
@property (nonatomic, assign ) MMPopupType type; // default is MMPopupTypeAlert.
@property (nonatomic, assign ) NSTimeInterval animationDuration; // default is 0.3 sec.
@property (nonatomic, assign ) BOOL withKeyboard; // default is NO. When YES, alert view with be shown with a center offset (only effect with MMPopupTypeAlert).
@property (nonatomic, copy ) MMPopupCompletionBlock showCompletionBlock; // show completion block.
@property (nonatomic, copy ) MMPopupCompletionBlock hideCompletionBlock; // hide completion block
@property (nonatomic, copy ) MMPopupBlock showAnimation; // custom show animation block.
@property (nonatomic, copy ) MMPopupBlock hideAnimation; // custom hide animation block.
/**
- override this method to show the keyboard if with a keyboard
*/
- (void) showKeyboard;
/**
- override this method to hide the keyboard if with a keyboard
*/
- (void) hideKeyboard;
/**
- show the popup view
*/
- (void) show;
/**
- show the popup view with completiom block
*
- @param block show completion block
*/
- (void) showWithBlock:(MMPopupCompletionBlock)block;
/**
- hide the popup view
*/
- (void) hide;
/**
- hide the popup view with completiom block
*
- @param block hide completion block
*/
- (void) hideWithBlock:(MMPopupCompletionBlock)block;
/**
- hide all popupview with current class, eg. [MMAlertview hideAll];
*/
- (void) hideAll;
@end</code></pre>
包括,PopupView 類型、時間、可見、show 與 hide 的block 事件等;
其中 - hideWithBlock 和 hideWithBlock 展現和隱藏 外部方法,并通過
其中 PopupView 內部也包含 alert、sheet、custom 的展現于隱藏的動畫事務;
- (MMPopupBlock)alertShowAnimation
(MMPopupBlock)alertHideAnimation
(MMPopupBlock)sheetShowAnimation
(MMPopupBlock)sheetHideAnimation
(MMPopupBlock)customShowAnimation
(MMPopupBlock)customHideAnimation</code></pre>
以 alertShowAnimation 為例:
- (MMPopupBlock)alertShowAnimation
{
MMWeakify(self);
MMPopupBlock block = ^(MMPopupView *popupView){
MMStrongify(self);
if ( !self.superview )
{
[self.attachedView.mm_dimBackgroundView addSubview:self];
[self mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.attachedView).centerOffset(CGPointMake(0, self.withKeyboard?-216/2:0));
}];
[self layoutIfNeeded];
}
self.layer.transform = CATransform3DMakeScale(1.2f, 1.2f, 1.0f);
self.alpha = 0.0f;
[UIView animateWithDuration:self.animationDuration
delay:0.0 options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.layer.transform = CATransform3DIdentity;
self.alpha = 1.0f;
} completion:^(BOOL finished) {
if ( self.showCompletionBlock )
{
self.showCompletionBlock(self, finished);
}
}];
};
return block;
}</code></pre>
添加到 將popupView 添加到 _attachedView 更新約束、渲染 并 執行相關動畫;
-
MMPopupView 核心拓展類定義如下:
@interface UIView (MMPopup)
@property (nonatomic, strong, readonly ) UIView *mm_dimBackgroundView;
@property (nonatomic, assign, readonly ) BOOL mm_dimBackgroundAnimating;
@property (nonatomic, assign ) NSTimeInterval mm_dimAnimationDuration;
@property (nonatomic, strong, readonly ) UIView *mm_dimBackgroundBlurView;
@property (nonatomic, assign ) BOOL mm_dimBackgroundBlurEnabled;
@property (nonatomic, assign ) UIBlurEffectStyle mm_dimBackgroundBlurEffectStyle;
- (void) mm_showDimBackground;
(void) mm_hideDimBackground;
(void) mm_distributeSpacingHorizontallyWith:(NSArray*)view;
- (void) mm_distributeSpacingVerticallyWith:(NSArray*)view;
@end</code></pre>
包括 MMPopWindow 已經 MMPopupView 的 subviews 新增、相關約束以及hide & show,這是整個類庫執行的最終落腳點
MMPopupView 幾點啟示
MMPopupView 源碼本身并不復雜,但仍然有許多可以借鑒學習的地方:
-
Objective-C Associated Objects 的實現原理
http://blog.leichunfeng.com/blog/2015/06/26/objective-c-associated-objects-implementation-principle/
-
如何自定義PopupView
-
二次封裝了 MMPopupView 的 簡單用法,參考如下:
UIViewController+MAC.h
@interface UIViewController(MAC)
pragma mark 設置 展示AlertView or SheetView
/**
- 展示Alert提示信息
/
-(void)showAlertMessage:(NSString)message;
/**
- 展示Alert提示信息
/
-(void)showAlertMessage:(NSString)message titile:(NSString *)title;
/**
- 展示Alert提示信息
*
- @param message 提示內容
- @param title 提示標題
- @param clickArr 按鈕信息數組
- @param clickIndex 點擊的下標
/
-(void)showAlertMessage:(NSString )message title:(NSString )title clickArr:(NSArray )arr click:(MMPopupItemHandler) clickIndex;
/**
- 展示SheetView提示信息
*
- @param title 提示標題
- @param clickArr 按鈕信息數組
- @param clickIndex 點擊的下標
/
-(void)showSheetTitle:(NSString )title clickArr:(NSArray *)arr click:(MMPopupItemHandler) clickIndex;</code></pre>
UIViewController+MAC.m
@implementation UIViewController(MAC)
-(void)showAlertMessage:(NSString*)message
{
[self showAlertMessage:message titile:@"提示"];
}
-(void)showAlertMessage:(NSString)message titile:(NSString )title{
MMPopupItemHandler block = ^(NSInteger index){
NSLog(@"clickd %@ button",@(index));
};
NSArray *items =
@[MMItemMake(@"確定", MMItemTypeHighlight, block)];
MMAlertView *alertView = [[MMAlertView alloc] initWithTitle:title
detail:message
items:items];
[alertView show];
}
-(void)showAlertMessage:(NSString )message title:(NSString )title clickArr:(NSArray )arr click:(MMPopupItemHandler) clickIndex{
if (!arr||arr.count<=0) {
return;
}
__block NSMutableArray items=[NSMutableArray array];
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL _Nonnull stop) {
[items addObject:MMItemMake(obj, MMItemTypeHighlight, clickIndex)];
}];
MMAlertView alertView = [[MMAlertView alloc] initWithTitle:title
detail:message
items:items];
[alertView show];
}
-(void)showSheetTitle:(NSString )title clickArr:(NSArray )arr click:(MMPopupItemHandler)clickIndex{
if (!arr||arr.count<=0) {
return;
}
__block NSMutableArray *items=[NSMutableArray array];
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[items addObject:MMItemMake(obj, MMItemTypeHighlight, clickIndex)];
}];
[[[MMSheetView alloc] initWithTitle:title
items:items] show];
};</code></pre>
來自:http://www.jianshu.com/p/c5ebd455ee82