《iOS編程(第四版)》Demo:HQLHypnoNerd

功能:在 HyponNerd 中聋丝,用戶可以在兩個視圖層次結構之間自由切換编振∽罕纾——第一個視圖層次結構用于催眠自己,第二個用于設置催眠提醒時間踪央。

要點:窗口臀玄、視圖控制器、延遲加載機制畅蹂、添加視圖健无、訪問視圖、UITabBarController 標簽頁視圖控制器液斜、UITextField 委托與文本輸入累贤、運動效果、使用調(diào)試器旗唁、本地通知畦浓、

Hypontize 截屏 Reminder 截屏

main() 與 UIApplication

用 Objective-C 語言編寫的程序的執(zhí)行入口與 C 語言相同,都是 main() 函數(shù):

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

UIApplicationMain 函數(shù):

  • 1?? 創(chuàng)建一個 UIApplication 對象(每個iOS應用都有且只有一個該對象)检疫,用于維護運行循環(huán)讶请。
  • 2?? UIApplicationMain 函數(shù)還會創(chuàng)建某個指定類的對象,并將其設置為 UIApplication 對象的 delegate屎媳,該對象的類是由 UIApplicationMain 函數(shù)得最后一個實參指定的夺溢,該實參的類型是 NSString 對象,代表的某個類的類名烛谊。
  • 以上代碼塊中风响,UIApplicationMain 會創(chuàng)建一個 AppDelegate 對象,并將其設置為 UIApplication 對象的 delegate丹禀。
  • 在應用啟動運行循環(huán)并開始接收事件前状勤,UIApplication 對象會向其委托發(fā)送一個特定的消息(didFinishLaunchingWithOptions:)完成相應的初始化工作,該方法只會在應用啟動完畢后調(diào)用一次双泪。

初始化方法實現(xiàn)在 AppDelegate.m 文件中:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

UIWindow

UIWindow 的常見用法示例:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  
    // 1.創(chuàng)建 UIWindow 實例持搜。
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    // 2.指定 UIWindow 對象的根視圖控制器。
    ViewController *viewController = [[ViewController alloc] init];
    self.window.rootViewController = viewController;

    // 3.設置背景色焙矛。
    self.window.backgroundColor = [UIColor whiteColor];

    // 4.設置 UIWindow 實例為主窗口并使其可見葫盼。
    [self.window makeKeyAndVisible];
  
    return YES;
}
  • UIWindow 對象提供了一個方法 setRootViewController 將視圖控制器的視圖層次結構加入應用窗口。當程序?qū)⒛硞€視圖控制器設置為 UIWindow 對象的 rootViewControl 時村斟,UIWindow 對象會將該視圖控制器的 view 作為子視圖加入窗口贫导,同時負責維護 viewController 和 view 對應的生命周期抛猫。此外,還會自動調(diào)整 view 的大小孩灯,將其設置為與窗口的大小相同闺金。
  • rootViewControl 的view需要在應用啟動完畢之后就顯示,所以 UIWindow 對象會在設置完 rootViewControl 后立刻加載其 view峰档。

UIWindow 的主要作用

  1. 作為 UIView 的最頂層容器掖看;包含應用顯示所需要的所有 UIVIew
  2. 傳遞觸摸消息和鍵盤事件給 UIView面哥;

WindowLevel

UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal;   // 層級:0
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert;    // 層級:1000
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar __TVOS_PROHIBITED;  // 層級:2000

視圖控制器

將視圖控制器作為子視圖添加到應用窗口(UIWindow)中。

視圖控制器是 UIViewController 類或其子類對象毅待。每個視圖控制器都負責管理一個視圖層次結構尚卫,包括視圖層次結構中的視圖并處理相關用戶事件,以及將整個視圖層次結構添加到應用窗口尸红。

UIViewController 的 view 屬性

view 屬性指向一個 UIView 對象吱涉。

UIViewController 對象可以管理一個視圖層次結構,view 就是這個視圖層次結構的根視圖外里,當程序?qū)?view 作為子視圖加入窗口時怎爵,也會加入 UIViewController 對象所管理的整個視圖層次結構。

根視圖控制器

UIWindow 對象提供了一個方法將視圖控制器的視圖層次結構加入應用窗口:setRootViewController盅蝗,當程序?qū)⒛硞€視圖控制器設置為 UIWindow 對象的 rootViewControl 時鳖链,UIWindow 對象會將該視圖控制器的view作為子視圖加入窗口,此外墩莫,還會自動調(diào)整view的大小芙委,將其設置為與窗口的大小相同。rootViewControl 的 view 需要在應用啟動完畢之后就顯示狂秦,所以 UIWindow 對象會在設置完rootViewControl 后立刻加載其 view 灌侣。

根視圖控制器創(chuàng)建步驟:

  1. 創(chuàng)建 UIViewController 的子類
    @interface myViewController : UIViewController

  2. AppDelegate.h 中聲明屬性
    @property (strong,nonatomic) UIViewController *viewController;

  3. AppDelegate.m 中實現(xiàn)初始化

    // 方法一:
    // 設置根視圖控制器
    BNRMyViewController *mvc = [[BNRyViewController alloc]init]; 
    self.window.rootViewController = mvc;
    
    // 方法二:
    // 獲取指向 NSbundle 對象的指針,該 NSBundle 對象代表應用程序的主程序包
    // mainBundle 主程序包對應于文件系統(tǒng)中項目的根目錄
    NSBundle *appBundle = [NSBundle mainBundle];
    // 告訴初始化方法在 appBundle 中查找 HQLReminderViewController.xib 文件
    self.viewController = [[myViewController alloc] initWithNibName:@"HQLReminderViewController" bundle: appBundle];
    //將 viewController 作為 window 的根視圖控制器
    self.window.rootViewController =self.viewController;
    

上述方法二中對【對象是通過 XIB 文件創(chuàng)建的根視圖控制器】設置同樣可使用方法一實現(xiàn)裂问,即:

HQLReminderViewController *rvc = [[HQLReminderViewController alloc] init];
self.window.rootViewController = rvc;

為什么向一個需要使用 NIB 文件的視圖控制器發(fā)送 init 消息也能成功加載對應的視圖侧啼?

  • initWithNibName:bundle:UIViewController 的指定初始化方法。
  • 向視圖控制器發(fā)送 init 消息會調(diào)用指定初始化方法 initWithNibName:bundle: 并為兩個參數(shù)都傳入nil堪簿。
  • 即使向一個需要使用 NIB 文件的視圖控制器發(fā)送 init 消息痊乾,UIViewControl 對象仍然會在應用程序中查找和當前 UIViewControl 子類同名的 XIB 文件。
  • ?? 因此建議為 【UIViewController 子類】和【該子類需要載入的NIB文件】取相同的名稱戴甩,這樣當視圖控制器需要加載視圖時符喝,會自動載入正確的 XIB 文件。

lazy loading 延遲加載視圖

  • 視圖控制器不會在其被創(chuàng)建出來的那一刻馬上創(chuàng)建并載入相應的視圖甜孤,只有當應用需要將某個視圖控制器的視圖顯示到屏幕上時协饲,相應的視圖控制器才會創(chuàng)建其視圖(提高內(nèi)存使用效率)蠕搜。
  • 也就是說,視圖控制器剛被創(chuàng)建時党远,其 view 屬性會被初始化為 nil卿吐。之后,當應用需要將視圖控制器的視圖顯示到屏幕上時而线,如果 view 屬性是 nil铭污,就會自動調(diào)用 loadview 方法。
  • ?? 為了實現(xiàn)視圖延遲加載膀篮,在initWithNibName:bundle:中不應該訪問 viewView 的任何子視圖嘹狞。凡是和 viewview 的子視圖有關的代碼,都應該在 viewDidLoad 方法中實現(xiàn)誓竿,避免加載不需要在屏幕上顯示的視圖磅网。
  • 視圖控制器可以通過兩種方式創(chuàng)建視圖層次結構:
    • 代碼方式:覆蓋 UIViewController 中的 loadView 方法
    • 文件方式:使用 interface builder 創(chuàng)建一個 NIB 文件,然后加入所需的視圖層次結構筷屡,最后視圖控制器會在運行時加載由該 NIB 文件編譯而成的 XIB 文件涧偷。
 - (void)loadView {  
        [super loadView];
   
    //創(chuàng)建一個 HQLHypnosisView 對象
    HQLHypnosisView *backgroundView = [[HQLHypnosisView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.view = backgroundView;
}
  • 上述代碼中,將 HQLHypnosisView 對象賦值給視圖控制器的 view 屬性毙死。

  • 子類視圖控制器中的 view 屬性繼承自 UIViewControl 對象:

    @property(null_resettable, nonatomic,strong) UIView *view;
    如果視圖還沒有被設置燎潮,那么 getter 方法會首先調(diào)用自身的 loadView 方法,如果重寫了 setter 或 getter 方法扼倘,子類必須調(diào)用父類确封。

UIView

添加視圖

frame 屬性:用于確定與視圖層次結構中其他視圖的相對位置,從而將自己的圖層與其他視圖的圖層正確組合屏幕上的圖像再菊。
bounds 屬性:用于確定繪制區(qū)域隅肥,避免將自己繪制到圖層邊界之外。
frame 屬性是從父視圖的坐標系統(tǒng)來看的袄简,而 bounds 屬性是從本身的坐標系統(tǒng)來看的.

frame與bounds的區(qū)別

視圖的相關結構:
Core Graphics( CG )

  • CGPoint:2D空間中的位置坐標,(x,y)
    生成函數(shù):CGPointMake(x,y)
  • CGSize:某個對象的尺寸:width腥放、height
    生成函數(shù):CGSizeMake(width,height)
  • CGRect:位置和尺寸:origin 和 size
    生成函數(shù):CGRectMake(x,y,width,height)
//創(chuàng)建一個CGRect結構
//CGRect firstFrame = CGRectMake(160, 240, 100, 150);
CGRect firstFrame = self.window.bounds;

//創(chuàng)建HQLHypnosisView對象
HQLHypnosisView *firstView = [[HQLHypnosisView alloc] initWithFrame:firstFrame];

//設置HQLHypnosisView背景色
firstView.backgroundColor = [UIColor greenColor];

//將HQLHypnosisView對象加入UIWindow對象
[self.window addSubview:firstView];

也可以在 HQLHypnosisView.m 中覆寫 initWithFrame: 方法設置 HQLHypnosisView 背景色。

- (instancetype)initWithFrame:(CGRect)frame {
    self =[super initWithFrame:frame];
    if (self) {
        //設置HQLHyponsisView對象的背景顏色為透明
        self.backgroundColor = [UIColor clearColor];
      }
    return self;
}

視圖層次的嵌套

HQLHypnosisView *secondView = [[HQLHypnosisView alloc] initWithFrame:secondFrame];
secondView.backgroundColor = [UIColor blueColor];

//將 secondView 添加到 window 上
[self.window addSubview:secondView];

//視圖層次嵌套
//視圖的frame所代表的位置是相對于其父視角的
//將 secondView 添加到 firstview 上
[firstView addSubview:secondView];

訪問視圖

通常情況下绿语,在用戶看到 XIB 文件中創(chuàng)建的視圖之前需要對它們做一些額外的初始化工作秃症。但是,關于視圖的初始化代碼不能寫在視圖控制器的初始化方法中—此時視圖控制器并未加載 NIB 文件吕粹,所有指向視圖的屬性都是 nil种柑。如果向這些屬性發(fā)送消息,雖然編譯時不會報錯匹耕,但是運行時無法對這些屬性做任何操作聚请。

兩種訪問 NIB 文件中視圖的方法:

  • -viewDidLoad: 該方法會在視圖控制器加載完視圖之后被調(diào)用,此時視圖控制器中所有視圖屬性都已經(jīng)指向了正確的視圖對象。
  • -viewWillAppear: 該方法會在視圖控制器的 view 添加到應用窗口之前被調(diào)用驶赏。
    區(qū)別: 如果只需要在應用啟動后設置一次視圖對象炸卑,就選擇 viewDidLoad;如果用戶每次看到視圖控制器的 view 時都需要對其進行設置煤傍,則選擇 viewWillAppear盖文。
  • 相反,viewWillDisappear:viewDidDisappear: 方法會在每次視圖控制器的 view 從屏幕上消失時被調(diào)用蚯姆。

設置啟動頁面延時

//延時3秒
[NSThread sleepForTimeInterval:3.0];

運動效果

iOS 設備內(nèi)嵌了許多功能強大的傳感器五续,例如加速傳感器,磁場傳感器和三軸陀螺儀等龄恋。應用可以通過這些傳感器了解設備的速度疙驾、方向和角度,并實現(xiàn)有用的功能郭毕。

例如荆萤,應用可以根據(jù)設備的方向自動將界面調(diào)整為橫排模式或豎排模式。從iOS 7開始铣卡,Apple 引入了一些新 API,可以輕松為應用添加一種通過感應器實現(xiàn)的視差(parallax)效果偏竟。

HQLHyponViewController.m 中修改drawHyponticMessage:方法煮落,為 UILabel 對象分別添加水平方向和垂直方向的視差效果,使 UILabel 對象的中心點坐標在每個方向上最多移動25點踊谋。

// 在屏幕隨機位置繪制20個 UILabel 對象
- (void)drawHypnoticMessage:(NSString *)message {
    for (int i =0; i<20; i++) {
        UILabel *messageLabel = [[UILabel alloc] init];
        // 設置UILabel對象的文字和顏色
        messageLabel.backgroundColor = [UIColor clearColor];
        messageLabel.textColor = [UIColor whiteColor];
        messageLabel.text = message;
        // 根據(jù)需要顯示的文字調(diào)整 UILabel 對象的大小
        [messageLabel sizeToFit];

        // 獲取隨機x坐標
        // 使 UILabel 對象的寬度不超出 HQLHyponsisViewController 的 view 的寬度
        int width = (int)(self.view.bounds.size.width - messageLabel.bounds.size.width);
        int x = arc4random() % width;

        // 獲取隨機y坐標
        // 使UILabel對象的高度不超出HQLHyponsisViewController的view的高度
        int height = (int)(self.view.bounds.size.width - messageLabel.bounds.size.height);
        int y =184 + arc4random() % height;

        // 設置 UILabel 對象的 frame
        CGRect frame = messageLabel.frame;
        frame.origin = CGPointMake(x, y);
        messageLabel.frame = frame;

        // 將UILabel對象添加到HQLHyponsisViewController的 view 中
        [self.view addSubview:messageLabel];

        // 運行效果:水平方向和垂直方向的視差效果
        // 設置 UILabel 對象的中心點坐標在每個方向上最多移動 25 點
        UIInterpolatingMotionEffect *motionEffect;
        motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
        motionEffect.minimumRelativeValue = @(-25);
        motionEffect.maximumRelativeValue = @(25);
        [messageLabel addMotionEffect:motionEffect];

        motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
        motionEffect.minimumRelativeValue = @(-25);
        motionEffect.maximumRelativeValue = @(25);
        [messageLabel addMotionEffect:motionEffect];  
}

LocalNotification(本地通知)

本地通知(local notification)用于向用戶提示一條消息蝉仇,即使應用沒有運行,用戶也可以收到本地通知殖蚕。
應用還可以通過后臺服務器實現(xiàn)推送通知(push notification).有關推送通知的技術細節(jié)請參考 Apple 的 Local and Push Notification Programming Guide(本地通知和推送通知編程指南)轿衔。
Demo:

locolNotification.gif

實現(xiàn)本地通知方法代碼如下:

- (IBAction)addReminder:(id)sender {
    
    NSDate *date = self.datePicker.date;
    NSLog(@"Setting a reminder for %@",date);
    
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]){
        
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
        
    }
    
    // 創(chuàng)建 UILocalNotification 對象
    UILocalNotification *note = [[UILocalNotification alloc] init];
    // 設置顯示內(nèi)容
    note.alertBody = @"Hypnotize me!";
    // 設置提醒時間
    note.fireDate = date;
    
    // 使用 scheduleLocalNotification: 方法注冊通知
    [[UIApplication sharedApplication] scheduleLocalNotification:note];
    
    NSLog(@"addReminder run over");
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市睦疫,隨后出現(xiàn)的幾起案子害驹,更是在濱河造成了極大的恐慌,老刑警劉巖蛤育,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宛官,死亡現(xiàn)場離奇詭異,居然都是意外死亡瓦糕,警方通過查閱死者的電腦和手機底洗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咕娄,“玉大人亥揖,你說我怎么就攤上這事∈ダ眨” “怎么了费变?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵摧扇,是天一觀的道長。 經(jīng)常有香客問我胡控,道長扳剿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任昼激,我火速辦了婚禮庇绽,結果婚禮上,老公的妹妹穿的比我還像新娘橙困。我一直安慰自己瞧掺,他們只是感情好,可當我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布凡傅。 她就那樣靜靜地躺著辟狈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夏跷。 梳的紋絲不亂的頭發(fā)上哼转,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音槽华,去河邊找鬼壹蔓。 笑死,一個胖子當著我的面吹牛猫态,可吹牛的內(nèi)容都是我干的佣蓉。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼亲雪,長吁一口氣:“原來是場噩夢啊……” “哼勇凭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起义辕,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤虾标,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后灌砖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夺巩,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年周崭,在試婚紗的時候發(fā)現(xiàn)自己被綠了柳譬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡续镇,死狀恐怖美澳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤制跟,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布舅桩,位于F島的核電站,受9級特大地震影響雨膨,放射性物質(zhì)發(fā)生泄漏擂涛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一聊记、第九天 我趴在偏房一處隱蔽的房頂上張望撒妈。 院中可真熱鬧,春花似錦排监、人聲如沸狰右。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棋蚌。三九已至,卻和暖如春挨队,著一層夾襖步出監(jiān)牢的瞬間谷暮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工盛垦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留湿弦,地道東北人。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓情臭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赌蔑。 傳聞我的和親對象是個殘疾皇子俯在,可洞房花燭夜當晚...
    茶點故事閱讀 43,576評論 2 349

推薦閱讀更多精彩內(nèi)容