KNSemiModalViewController——呈現半模態視圖

                            ?????? 

以下內容來源于官方源碼、 README 文檔、測試 Demo或個人使用總結 !

UIViewController+KNSemiModal Category

UIViewController+KNSemiModal is an effort to make a replica of semi-modal view with pushed-back stacked animation found in the beautiful Park Guides by National Geographic app. You can see this original semi-modal view below.

This library (ARC) is designed as a Category to UIViewController so you don't have to subclass and you can simply drop in any project and it will just work!

UIViewController+KNSemiModal 可以實現半模態視圖的堆疊效果,使用范疇(Category)實現,代碼侵入性較小。

Original screenshot

.

Replica (view demo video to see the beautiful animation)*

.

On iPad

Features

  • Works with bare UIViewController
  • Works with UIViewController contained inside UINavigationController
  • Works with UIViewController contained inside UINavigationController, contained inside UITabbarController
  • Auto handling of modal frame size
  • Auto handling of touch area for dismissal
  • Resizable after presenting so that keyboard related interactions are possible
  • Easy to understand and very small code base, only 2 files
  • Trivial to implement as subclass
  • Landscape support (not during presentation)
  • Only use basic CAAnimation
  • iPad support (experimental)
  • Minimum iOS 5.0 (if you need 4.x support, use older commits before Jan 2013)

Optional parameters

  • animation duration
  • parent alpha
  • optional push-back
  • shadow opacity
  • disabling the cancel action
  • transition style: slide up, fade

Easily extend this to anything you would want to make configurable. Feel free to submit pull requests.

可選參數:

// 結構,相關的配置參數
extern const struct KNSemiModalOptionKeys {
    __unsafe_unretained NSString *traverseParentHierarchy; // 遍歷父層次結構,BOOL類型. default is YES.
    __unsafe_unretained NSString *pushParentBack;          // 推回父視圖,BOOL類型. default is YES.
    __unsafe_unretained NSString *animationDuration; // 動畫延時,double 類型, in seconds. default is 0.5.
    __unsafe_unretained NSString *parentAlpha;       // 父視圖透明度,float 類型.值越小越暗. default is 0.5.
    __unsafe_unretained NSString *parentScale;       // 父視圖縮放比例,double 類型 default is 0.8
    __unsafe_unretained NSString *shadowOpacity;     // 陰影不透明度,default is 0.8
    __unsafe_unretained NSString *transitionStyle;   // 動畫類型,NSNumber 類型
    __unsafe_unretained NSString *disableCancel;     // 是否禁用取消,BOOL 類型,default is NO.
    __unsafe_unretained NSString *backgroundView;    // 自定義背景視圖,UIView 類型
} KNSemiModalOptionKeys;

// 動畫類型
NS_ENUM(NSUInteger, KNSemiModalTransitionStyle) {
    KNSemiModalTransitionStyleSlideUp,      // 向上滑動
    KNSemiModalTransitionStyleFadeInOut,    // 淡入淡出
    KNSemiModalTransitionStyleFadeIn,       // 淡入
    KNSemiModalTransitionStyleFadeOut,      // 淡出
};

// 使用時要根據指定類型封裝
-(void)kn_registerDefaultsAndOptions:(NSDictionary*)options {
    [self ym_registerOptions:options defaults:@{
     KNSemiModalOptionKeys.traverseParentHierarchy : @(YES),
     KNSemiModalOptionKeys.pushParentBack : @(YES),
     KNSemiModalOptionKeys.animationDuration : @(0.5),
     KNSemiModalOptionKeys.parentAlpha : @(0.5),
     KNSemiModalOptionKeys.parentScale : @(0.8),     
     KNSemiModalOptionKeys.shadowOpacity : @(0.8),
     KNSemiModalOptionKeys.transitionStyle : @(KNSemiModalTransitionStyleSlideUp),
     KNSemiModalOptionKeys.disableCancel : @(NO),
     }];
}

    NSDictionary *options = @{
                  // 遍歷父層次結構,BOOL類型. default is YES.
                  KNSemiModalOptionKeys.traverseParentHierarchy:@(YES),
                  // 父視圖后移動畫,BOOL類型. default is YES.
                  KNSemiModalOptionKeys.pushParentBack:@(NO),
                  // 動畫延時,double 類型. in seconds. default is 0.5.
                  KNSemiModalOptionKeys.animationDuration:@(0.25),
                  // 父視圖透明度,float 類型.值越小越暗. default is 0.5.
                  KNSemiModalOptionKeys.parentAlpha:@(0.5),
                  // 父視圖縮放比例,double 類型 default is 0.8
                  KNSemiModalOptionKeys.parentScale:@(1),
                  // 陰影不透明度,default is 0.8
                  KNSemiModalOptionKeys.shadowOpacity:@(0.6),
                  // 動畫類型,NSNumber 類型
                  KNSemiModalOptionKeys.transitionStyle:        @(KNSemiModalTransitionStyleFadeInOut),
                  // 是否禁用取消,BOOL 類型,default is NO.
                  KNSemiModalOptionKeys.disableCancel:@(NO),
                  // 自定義背景視圖,UIView 類型
                  KNSemiModalOptionKeys.backgroundView:[UIView new]
                              };

Installation / How to use

  • Copy 4 files in Source folder to your project
  • Add QuartzCore.framework to your project
  • #import "UIViewController+KNSemiModal.h" in your ViewController
  • Call [self presentSemiModalView:myView]
  • Call [self dismissSemiModalView] either from parent/presenting or child/presented controller

使用

官方 Demo1

顯示視圖

- (IBAction)buttonDidTouch:(id)sender {
  // 你可以呈現一個簡單的 UIImageView 或任何其他的 UIView ,而且不需要關心關閉方法
  UIImageView * imagev = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"temp.jpg"]];
  UIImageView * bgimgv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background_01"]];
  [self presentSemiView:imagev
            withOptions:@{
                          KNSemiModalOptionKeys.backgroundView:bgimgv
                          }];
}

官方 Demo2:

顯示大小可以改變的視圖

部分代碼:

@implementation KNSecondViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
      self.title = @"Second";
      self.tabBarItem.image = [UIImage imageNamed:@"second"];

      // 請注意,你需要擁有正在呈現的ViewController的所有權
      semiVC = [[KNThirdViewController alloc] initWithNibName:@"KNThirdViewController" bundle:nil];

      // 您可以選擇收聽通知
      // 視圖顯示完成后
      [[NSNotificationCenter defaultCenter] addObserver:self
                                               selector:@selector(semiModalPresented:)
                                                   name:kSemiModalDidShowNotification
                                                 object:nil];
      // 視圖隱藏后
      [[NSNotificationCenter defaultCenter] addObserver:self
                                               selector:@selector(semiModalDismissed:)
                                                   name:kSemiModalDidHideNotification
                                                 object:nil];
      // 視圖被重新調整大小后
      [[NSNotificationCenter defaultCenter] addObserver:self
                                               selector:@selector(semiModalResized:)
                                                   name:kSemiModalWasResizedNotification
                                                 object:nil];
    }
    return self;
}

#pragma mark - Demo

- (IBAction)buttonDidTouch:(id)sender {

  // You can also present a UIViewController with complex views in it
  // and optionally containing an explicit dismiss button for semi modal
  [self presentSemiViewController:semiVC withOptions:@{
         KNSemiModalOptionKeys.pushParentBack    : @(YES),
         KNSemiModalOptionKeys.animationDuration : @(2.0),
         KNSemiModalOptionKeys.shadowOpacity     : @(0.3),
     }];

}

#pragma mark - Optional notifications

- (void) semiModalResized:(NSNotification *) notification {
  if(notification.object == self){
    NSLog(@"The view controller presented was been resized");
  }
}

- (void)semiModalPresented:(NSNotification *) notification {
  if (notification.object == self) {
    NSLog(@"This view controller just shown a view with semi modal annimation");
  }
}
- (void)semiModalDismissed:(NSNotification *) notification {
  if (notification.object == self) {
    NSLog(@"A view controller was dismissed with semi modal annimation");
  }
}

-(void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

被呈現視圖控制器中的動作方法

// 關閉視圖
- (IBAction)dismissButtonDidTouch:(id)sender {

  // 調用父控件ViewController 以關閉視圖
  // 視圖層次結構要小心
  UIViewController * parent = [self.view containingViewController];
  if ([parent respondsToSelector:@selector(dismissSemiModalView)]) {
    [parent dismissSemiModalView];
  }

}

// 重新設置大小
- (IBAction)resizeSemiModalView:(id)sender {
  UIViewController * parent = [self.view containingViewController];
  if ([parent respondsToSelector:@selector(resizeSemiView:)]) {
    [parent resizeSemiView:CGSizeMake(320, arc4random() % 280 + 180)];
  }
}

官方 Demo3:

顯示 tableView 列表:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  [tableView deselectRowAtIndexPath:indexPath animated:NO];

  // You have to retain the ownership of ViewController that you are presenting
  // ??必須要保留被呈現視圖控制器的擁有權
  // ??就是說被呈現的視圖控制器要設置成它的屬性或者實例對象
  [self presentSemiViewController:modalVC
                      withOptions:@{
                     KNSemiModalOptionKeys.pushParentBack : @(NO),
                     KNSemiModalOptionKeys.parentAlpha : @(0.8)
                                    }];
  
  // 以下的代碼是無效的
//  KNModalTableViewController * vc = [[KNModalTableViewController alloc] initWithStyle:UITableViewStylePlain];
//  [self presentSemiViewController:vc];
}

TableView 的 frame 屬性在其指定初始化方法中設置:

- (id)initWithStyle:(UITableViewStyle)style {
  self = [super initWithStyle:style];
  if (self) {
    // 設置 frame
    self.view.frame = CGRectMake(0, 0, 320, 200);
  }
  return self;
}

以模態方式顯示一張圖片

實現代碼:

- (IBAction)buttonDidClicked:(id)sender {
    
    // 加載圖片方式一,有緩存
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"boat"]];
    // 加載圖片方式二,無緩存
    // NSString *path = [[NSBundle mainBundle] pathForResource:@"boat" ofType:@"png"];
    // UIImage *fileImage = [UIImage imageWithContentsOfFile:path];

    NSDictionary *options = @{
                  // 父視圖后移動畫,BOOL類型. default is YES.
                  KNSemiModalOptionKeys.pushParentBack:         @(NO),
                  // 動畫延時,double 類型. in seconds. default is 0.5.
                  KNSemiModalOptionKeys.animationDuration:      @(0.25),
                  // 父視圖透明度,float 類型.值越小越暗. default is 0.5.
                  KNSemiModalOptionKeys.parentAlpha:            @(0.5),
                  // 父視圖縮放比例,double 類型 default is 0.8
                  KNSemiModalOptionKeys.parentScale:            @(1),
                  // 陰影不透明度,default is 0.8
                  KNSemiModalOptionKeys.shadowOpacity:          @(0.6),
                  // 動畫類型,NSNumber 類型
                  KNSemiModalOptionKeys.transitionStyle:        @(KNSemiModalTransitionStyleFadeInOut),
                  // 是否禁用取消,BOOL 類型,default is NO.
                  KNSemiModalOptionKeys.disableCancel:          @(NO),
                              };
    [self presentSemiView:imageView withOptions:options completion:^{
        NSLog(@"completion!");
    }];
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容