處理文本輸入框的輸入事件,單擊文本輸入框後要彈出鍵盤。網絡
彈出鍵盤有兩種實現方式:一種代理,一種通知。也就是對應的(觀察者模式和代理模式)。ide
每個應用程序都有一個通知中心(NSNotificationCenter)實例,專門負責協助不一樣對象之間的消息通訊。post
任何一個對象均可以向通知中心發佈通知(NSNotification),描述本身在作什麼。動畫
其餘感興趣的對象(Observer)能夠申請在某個特定通知發佈時(或在某個特定的對象發佈通知時)收到這個通知。atom
通知中心(NSNotificationCenter)提供了相應的方法來幫助發佈通知
- (void)postNotification:(NSNotification *)notification;
發佈一個notification通知,可在notification對象中設置通知的名稱、通知發佈者、額外信息等spa
- (void)postNotificationName:(NSString *)aName object:(id)anObject;
發佈一個名稱爲aName的通知,anObject爲這個通知的發佈者3d
- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
發佈一個名稱爲aName的通知,anObject爲這個通知的發佈者,aUserInfo爲額外信息代理
通知中心(NSNotificationCenter)提供了方法來註冊一個監聽通知的監聽器(Observer)
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
observer:監聽器,即誰要接收這個通知
aSelector:收到通知後,回調監聽器的這個方法,而且把通知對象當作參數傳入
aName:通知的名稱。若是爲nil,那麼不管通知的名稱是什麼,監聽器都能收到這個通知
anObject:通知發佈者。若是爲anObject和aName都爲nil,監聽器都收到全部的通知server
- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block;
name:通知的名稱
obj:通知發佈者
block:收到對應的通知時,會回調這個block
queue:決定了block在哪一個操做隊列中執行,若是傳nil,默認在當前操做隊列中同步執行對象
通知中心不會保留(retain)監聽器對象,在通知中心註冊過的對象,必須在該對象釋放前取消註冊。不然,當相應的通知再次出現時,通知中心仍然會向該監聽器發送消息。由於相應的監聽器對象已經被釋放了,因此可能會致使應用崩潰。
通知中心提供了相應的方法來取消註冊監聽器
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;
實現過程:先註冊消息 postNotificationName ,而後在響應的方法的接收消息 addObserver,最後實現接收消息的方法
由於在系統中又定義好的鍵盤處理通知,因此直接進行監聽就好了。
UIKIT_EXTERN NSString *const UIKeyboardWillShowNotification; // 即將彈出
UIKIT_EXTERN NSString *const UIKeyboardDidShowNotification; // 顯示
UIKIT_EXTERN NSString *const UIKeyboardWillHideNotification; //即將隱藏
UIKIT_EXTERN NSString *const UIKeyboardDidHideNotification; // 隱藏
// 一、經過通知監聽鍵盤出現消息
// 添加監聽器,監聽鍵盤彈出
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardComeout:) name:UIKeyboardWillShowNotificationobject:nil];
// 添加監聽器,監聽鍵盤退出
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(keyboardGoaway:) name:UIKeyboardWillHideNotificationobject:nil];
// 二、響應通知的方法,顯示鍵盤
- (void)keyboardComeout:(NSNotification *)note
{
NSLog(@"keyboardComeout--\n%@",note);
// 取出消息中鍵盤出現後的最終位置,要將字典對象轉換成CGRect
CGRect rect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
self.viewBotom.constant = rect.size.height;
// 取出鍵盤彈出所須要的時間
double animateTime = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIViewanimateWithDuration:animateTime animations:^{
[self.viewlayoutIfNeeded];
}];
/**
* NSNotification 內部信息
NSConcreteNotification 0x7f896bebf4d0 {name = UIKeyboardWillShowNotification; userInfo = {
UIKeyboardAnimationCurveUserInfoKey = 7;
UIKeyboardAnimationDurationUserInfoKey = "0.25";
UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {375, 225}}";
UIKeyboardCenterBeginUserInfoKey = "NSPoint: {187.5, 779.5}";
UIKeyboardCenterEndUserInfoKey = "NSPoint: {187.5, 554.5}";
UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 667}, {375, 225}}";
UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 442}, {375, 225}}";
}}
*/
}
/**
* 三、開始滾動界面後隱藏鍵盤
*/
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//退出鍵盤
// NSLog(@"scrollViewWillBeginDragging--");
//[self.view endEditing:YES];//方法1
[self.textField resignFirstResponder]; // 方法2:誰響應的鍵盤,誰就能夠調用這個方法退出鍵盤(resignFirstResponder)
}
// 隱藏鍵盤
- (void)keyboardGoaway:(NSNotification *)note
{
NSLog(@"keyboardGoaway--\n%@",note);
self.viewBotom.constant = 0;
//取出鍵盤彈出所須要的時間
double animateTime = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIViewanimateWithDuration:animateTime animations:^{
[self.viewlayoutIfNeeded];
}];
}
看彈出效果,實際效果是有動畫的,過渡更好。
這裏使用更新控件的約束來實現view的移動。
以下屬性:
@property (weak, nonatomic) IBOutletNSLayoutConstraint *viewBotom;
而後控制約束的constant值,就能夠實現view的移動。
設置方法方法:
// 取出消息中鍵盤出現後的最終位置,要將字典對象轉換成CGRect
CGRect rect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
self.viewBotom.constant = rect.size.height;
直接使用其自帶的功能便可
// 設置文本框左邊的內容
UIView *leftView = [[UIView alloc] init];
leftView.frame = CGRectMake(0, 0, 10, 0);
self.messageField.leftView = leftView;
self.messageField.leftViewMode = UITextFieldViewModeAlways;
// 右邊間距
self.messageField.rightView = leftView;
self.messageField.rightViewMode = UITextFieldViewModeAlways;
- (void)dealloc
{
// 使用完畢後要手動移除監聽對象
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
一、在頭文件中實現代理,定義協議
二、使用方法:1 設置代理,2 遵照協議,3 實現方法
三、規範:參考蘋果官方的協議實現方式
四、做用:
一、監聽事件:A是監聽B的一些行爲,則A成爲B的代理
二、消息傳遞:A想告訴B一些事情,則B成爲A的代理
五、總結:
一、若是想監聽別人的一些行爲,那麼就要成爲別人的代理
二、若是你想告訴別人一些事情,那麼就讓別人成爲你得代理
六、開發步驟
一、擬一份協議(格式:控件名 + Delegate),在協議裏聲明一些代理方法(通常代理方法都是@optional)
二、聲明一個代理屬性(弱引用) @property (weak,nonatomic) id delegate;
三、在內部發生某些行爲時,調用代理對應的代理方法,通知代理內部發生了什麼事情
四、設置代理: xxx.delegate = self;
五、 yyy對象遵照協議,實現代理方法
先看效果
首先在xib裏實現界面以下:
而後實現文件也比較簡單,在點擊過加載按鈕後,由此對象給代理髮送加載數據通知。
頭文件實現裏包括代理所遵照協議的定義,包括一個可用方法。
@classSLQLoadData;
@protocol SLQLoadDataDelegate <NSObject>
@optional
/**
* 代理方法:點擊按鈕操做
*/
- (void)LoadDataDidCilckButton:(SLQLoadData *)loadData;
@interface SLQLoadData : UIView
// 代理屬性
@property (weak,nonatomic) id<SLQLoadDataDelegate> delegate;
+ (instancetype)loadData;// 返回加載對象
- (void)endingloadData; // 結束加載
@end
#import "SLQLoadData.h"
@interfaceSLQLoadData ()
- (IBAction)loadMoreData:(id)sender;
@property (weak, nonatomic) IBOutletUIView *loadView; // 正在加載界面
@property (weak, nonatomic) IBOutletUIButton *loadBtn; // 加載按鈕
@end
@implementation SLQLoadData
+ (instancetype)loadData
{
// NSStringFromClass 將類名轉換成字符串,xib文件名和類名同樣
return [[[NSBundlemainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
}
- (IBAction)loadMoreData:(id)sender
{
// 模擬從網絡加載數據
//NSLog(@「loadMoreData」);
self.loadView.hidden = NO;
self.loadBtn.hidden = YES;
// 發送消息到代理對象,首先判斷代理方法是否存在
if ([self.delegate respondsToSelector:@selector(LoadDataDidCilckButton:)])
{
[self.delegate LoadDataDidCilckButton:self];
}
}
// 隱藏正在加載界面
- (void)endingloadData
{
self.loadView.hidden = YES;
self.loadBtn.hidden = NO;
}
@end
一、包含頭文件並遵照協議
#import "SLQLoadData.h"
@interfaceViewController () <SLQLoadDataDelegate> // 遵照代理協議
二、指定代理對象
SLQLoadData *loadData = [SLQLoadData loadData];
// 指定控制器爲代理對象
loadData.delegate = self;
self.tableView.tableFooterView = loadData;
三、實現代理方法
// 實現代理方法
- (void)LoadDataDidCilckButton:(SLQLoadData *)loadData
{
NSLog(@"LoadDataDidCilckButton");
// 模擬從網絡加載數據,加一個定時器
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
SLQFengNews *news = [[SLQFengNews alloc] init];
news.title = @"高考往事";
news.topic = NO;
news.image = @"ad_02";
news.comment = @"13489";
// 添加至模型對象
[self.news addObject:news];
// 刷新表格
[self.tableView reloadData];
// 隱藏loadView
SLQLoadData *load = (SLQLoadData *)self.tableView.tableFooterView;
[load endingloadData];
});
}
其餘系統自帶通知
UIDevice類提供了一個單例對象,它表明着設備,經過它能夠得到一些設備相關的信息,好比電池電量值(batteryLevel)、電池狀態(batteryState)、設備的類型(model,好比iPod、iPhone等)、設備的系統(systemVersion)
經過[UIDevice currentDevice]能夠獲取這個單例對象
UIDevice對象會不間斷地發佈一些通知,下列是UIDevice對象所發佈通知的名稱常量:
UIDeviceOrientationDidChangeNotification // 設備旋轉
UIDeviceBatteryStateDidChangeNotification // 電池狀態改變
UIDeviceBatteryLevelDidChangeNotification // 電池電量改變
UIDeviceProximityStateDidChangeNotification // 近距離傳感器(好比設備貼近了使用者的臉部)
鍵盤通知
咱們常常須要在鍵盤彈出或者隱藏的時候作一些特定的操做,所以須要監聽鍵盤的狀態
鍵盤狀態改變的時候,系統會發出一些特定的通知
UIKeyboardWillShowNotification // 鍵盤即將顯示
UIKeyboardDidShowNotification // 鍵盤顯示完畢
UIKeyboardWillHideNotification // 鍵盤即將隱藏
UIKeyboardDidHideNotification // 鍵盤隱藏完畢
UIKeyboardWillChangeFrameNotification // 鍵盤的位置尺寸即將發生改變
UIKeyboardDidChangeFrameNotification // 鍵盤的位置尺寸改變完畢
系統發出鍵盤通知時,會附帶一下跟鍵盤有關的額外信息(字典),字典常見的key以下:
UIKeyboardFrameBeginUserInfoKey // 鍵盤剛開始的frame
UIKeyboardFrameEndUserInfoKey // 鍵盤最終的frame(動畫執行完畢後)
UIKeyboardAnimationDurationUserInfoKey // 鍵盤動畫的時間
UIKeyboardAnimationCurveUserInfoKey // 鍵盤動畫的執行節奏(快慢)
代理和通知比較
共同點
利用通知和代理都能完成對象之間的通訊(好比A對象告訴D對象發生了什麼事情, A對象傳遞數據給D對象)
不一樣點
代理 : 1個對象只能告訴另1個對象發生了什麼事情
通知 : 1個對象能告訴N個對象發生了什麼事情, 1個對象能得知N個對象發生了什麼事情