先從最基本的研究起,用一個例子來說明,如何建立一個UIScrollView。
在xcode建立一個基於視圖的工程,然後開啟項目裡viewController的xib檔案,在view裡添加一個uiscrollview,然後安一定間距拖幾個button、textfield之類的到scrollview
裡,這樣ui基本的架構就完成了。
下面就是代碼部分了:
UIScrollViewDemoViewController.h
#import <UIKit/UIKit.h>@interface UIScrollViewDemoViewController : UIViewController<UITextFieldDelegate,UIScrollViewDelegate> { IBOutlet UIScrollView * myScrollView; UITextField * activeField; CGFloat oldContentOffsetValue; IBOutlet UITextField * textFieldOne; IBOutlet UITextField * textFieldTwo; IBOutlet UITextField * textFieldThree; IBOutlet UITextField * textFieldFour; BOOL keyboardShown; BOOL isNeedSetOffset; }@property (nonatomic,retain) UITextField * activeField;@end
上面代碼裡,我xib檔案建立了五個iboutlet變數,分別是四個textfield和一個scrollview,然後就可以到xib檔案裡,把它們和對應的ui相串連趕來。
其它的變數在實現檔案裡會用到。
UIScrollViewDemoViewController.m
#import "UIScrollViewDemoViewController.h"@implementation UIScrollViewDemoViewController@synthesize activeField;- (void)dealloc{ [myScrollView release]; [activeField release]; [textFieldOne release]; [textFieldTwo release]; [textFieldThree release]; [textFieldFour release]; [super dealloc];}- (void)didReceiveMemoryWarning{ // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use.}#pragma mark - View lifecycle// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.- (void)viewDidLoad{ [super viewDidLoad]; textFieldOne.delegate = self; textFieldTwo.delegate = self; textFieldThree.delegate = self; textFieldFour.delegate = self; myScrollView.contentSize = CGSizeMake(myScrollView.frame.size.width, 1400.0f); myScrollView.scrollEnabled = YES; myScrollView.delegate = self; keyboardShown = NO; [self performSelector:@selector(registerForKeyboardNotifications)]; }- (void)viewDidUnload{ [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil;}- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait);}#pragma mark - UITextField Delegate-(void)textFieldDidBeginEditing:(UITextField *)textField{ activeField = textField;}-(void)textFieldDidEndEditing:(UITextField *)textField{ activeField = nil;}-(BOOL)textFieldShouldReturn:(UITextField *)textField{ [textField resignFirstResponder]; return YES;}#pragma mark -Keyboard Helper Method// Call this method somewhere in your view controller setup code.- (void)registerForKeyboardNotifications{ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasHidden:) name:UIKeyboardDidHideNotification object:nil];}// Called when the UIKeyboardDidShowNotification is sent.- (void)keyboardWasShown:(NSNotification*)aNotification{ NSLog(@"-------"); if (keyboardShown) return; NSDictionary* info = [aNotification userInfo]; // Get the size of the keyboard. NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; // Resize the scroll view (which is the root view of the window) CGRect viewFrame = [myScrollView frame]; viewFrame.size.height -= keyboardSize.height; myScrollView.frame = viewFrame; // Scroll the active text field into view. CGRect textFieldRect = [activeField frame]; [myScrollView scrollRectToVisible:textFieldRect animated:YES]; oldContentOffsetValue = [myScrollView contentOffset].y; CGFloat value = (activeField.frame.origin.y+myScrollView.frame.origin.y+activeField.frame.size.height - self.view.frame.size.height + keyboardSize.height)+2.0f; if (value > 0) { [myScrollView setContentOffset:CGPointMake(0, value) animated:YES]; isNeedSetOffset = YES; } keyboardShown = YES;}// Called when the UIKeyboardDidHideNotification is sent- (void)keyboardWasHidden:(NSNotification*)aNotification{ NSDictionary* info = [aNotification userInfo]; // Get the size of the keyboard. NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; // Reset the height of the scroll view to its original value CGRect viewFrame = [myScrollView frame]; viewFrame.size.height += keyboardSize.height; myScrollView.frame = viewFrame; if (isNeedSetOffset) { [myScrollView setContentOffset:CGPointMake(0, oldContentOffsetValue) animated:YES]; } isNeedSetOffset = NO; keyboardShown = NO;}@end
代碼有點長,一步步解析吧。
首先是viewDidLoad方法裡進行一些初始化處理:
- (void)viewDidLoad{ [super viewDidLoad]; textFieldOne.delegate = self;//設定textField的delegate,主要是為了顯示和隱藏彈出的鍵盤用的 textFieldTwo.delegate = self; textFieldThree.delegate = self; textFieldFour.delegate = self; //使用scrollView很關鍵的地方,設定contentSize,一般是安你的scrollView的size來設定,後面的height可以適當多個300~400 myScrollView.contentSize = CGSizeMake(myScrollView.frame.size.width, 1400.0f); myScrollView.scrollEnabled = YES;//這個預設就是YES,這裡多餘了。 myScrollView.delegate = self;//設定scrollView的delegate,需要監聽滾動事件的可以實現它的delegate方法 keyboardShown = NO;//一個狀態標誌,主要用來標識鍵盤的顯隱狀態 [self performSelector:@selector(registerForKeyboardNotifications)];//這個方法用來處理當textField被自己彈出的鍵盤擋住時,把它滾動到適當位置 }
接著就是相應的
registerForKeyboardNotifications方法,用來把textField滾動到適當的位置。
- (void)registerForKeyboardNotifications{ //添加自己做為觀察者,以擷取鍵盤顯示時的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; //添加自己做為觀察者,以擷取鍵盤隱藏時的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasHidden:) name:UIKeyboardDidHideNotification object:nil];}// 鍵盤出現時調用此方法- (void)keyboardWasShown:(NSNotification*)aNotification{ //如果鍵盤是顯示狀態,不用做重複的操作 if (keyboardShown) return; //獲得鍵盤通知的使用者資訊字典 NSDictionary* info = [aNotification userInfo]; // 取得鍵盤尺寸. NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; // 重新設定scrollView的size CGRect viewFrame = [myScrollView frame]; viewFrame.size.height -= keyboardSize.height; myScrollView.frame = viewFrame; // 把當前被擋住的text field滾動到view中適當的可見位置. CGRect textFieldRect = [activeField frame]; [myScrollView scrollRectToVisible:textFieldRect animated:YES]; //記錄當前textField的位移量,方便隱藏鍵盤時,恢複textField到原來位置 oldContentOffsetValue = [myScrollView contentOffset].y; //計算textField滾動到的適當位置 CGFloat value = (activeField.frame.origin.y+myScrollView.frame.origin.y+activeField.frame.size.height - self.view.frame.size.height + keyboardSize.height)+2.0f; //value>0則表示需要滾動,小於0表示當前textField沒有被擋住,不需要滾動 if (value > 0) { //使textField滾動到適當位置 [myScrollView setContentOffset:CGPointMake(0, value) animated:YES]; isNeedSetOffset = YES;//更改狀態標誌為需要滾動 } //更改鍵盤狀態標誌為已顯示 keyboardShown = YES;}// 鍵盤隱藏時調用此方法- (void)keyboardWasHidden:(NSNotification*)aNotification{ NSDictionary* info = [aNotification userInfo]; // Get the size of the keyboard. NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey]; CGSize keyboardSize = [aValue CGRectValue].size; // Reset the height of the scroll view to its original value CGRect viewFrame = [myScrollView frame]; viewFrame.size.height += keyboardSize.height; myScrollView.frame = viewFrame; //如果狀態標誌為需要滾動,則要執行textFiled複位操作 if (isNeedSetOffset) { //oldContentOffsetValue記錄了textField原來的位置,複位即可 [myScrollView setContentOffset:CGPointMake(0, oldContentOffsetValue) animated:YES]; } //複位狀態標誌 isNeedSetOffset = NO; keyboardShown = NO;}
這樣一個簡單的scrollView就做好了,滾動被擋住的內容到適當位置也是很常用的功能。