星期四, 2月 02, 2012

ios iphone/ipad Dev 學習筆記 (A-09) Move up (scroll up) UItextField when keyboard is present

當一個畫面裏需要 user 填入資料的元件太多,就會面臨一個問題:
  當螢幕鍵盤被打開,靠螢幕下方的欄位元件就會被擋住。
這個問題可以利用 UIScrollView 來解決。


HomeViewCtrl.h

  #import <UIKit/UIKit.h>
  
  //注意,這裡要宣告 實作 UITextFieldDelegate 相關的 method
  @interface HomeViewCtrl : UIViewController<UITextFieldDelegate>{
      UITextField * currentTextField;
      BOOL keyboardIsShown;
  }

  @property(nonatomic, strong) UIScrollView * scrollView;
  @property(nonatomic, strong) UILabel * label;
  @property(nonatomic, strong) UITextField * textField;

  @end



HomeViewCtrl.m

  #import "HomeViewCtrl.h"

  @implementation HomeViewCtrl

  @synthesize scrollView, label, textField;

  - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  {
      self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
      if (self) {
          // Custom initialization
      }
      return self;
  }

  - (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.
  }

  // Implement viewDidLoad to do additional setup after loading the view,   typically from a nib.
  - (void)viewDidLoad
  {
      //取得螢幕的尺寸
      //bounds = 螢幕範圍
      //applicationFrame = bounds 扣除狀態列所佔據的空間
      CGRect screenRect = [[UIScreen mainScreen] applicationFrame];     
      CGFloat screenWidth = screenRect.size.width;
      CGFloat screenHeight = screenRect.size.height;

      //配置 scrollView
      //這一次我把 scrollView frame size content size 設成一樣大,
      //所以在程式剛進入的時間點如果去拖動 view,是沒有捲動的效果的
      scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)]; //設定 scrollView 的外觀尺寸
      scrollView.contentSize = CGSizeMake(screenWidth, screenHeight); //設定 scrollView 內容的空間尺寸
    
      scrollView.scrollEnabled = YES;
    
      [self.view addSubview:scrollView];
      // self.view = scrollView  // 這是另一種掛上 scrollView 的方式
    
      //配置 label,以便提供視覺參考
      label = [[UILabel alloc] initWithFrame:CGRectMake(80, 100, 150, 50)];
      label.text = @"ScrollView Test";
      [self.scrollView addSubview:label];


      //配置 textField,為了要做測試,要把這個元件放到靠近螢幕下方的位置
      textField = [[UITextField alloc] initWithFrame:CGRectMake(50, (screenHeight-100), 200, 50)];
      textField.borderStyle = UITextBorderStyleRoundedRect;
      textField.returnKeyType = UIReturnKeyDone;
      textField.delegate = self;
      [self.scrollView addSubview:textField];
        
      [super viewDidLoad];
  }


  - (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);
  }


  // 跟系統註冊申請 keyboard notification
  // 注意:selector 的名稱包含 『:』
  -(void) viewWillAppear:(BOOL)animated
  {
      //向系統註冊,請系統將 keyboardDidShow: 的訊息送過來給我 (self)
      [[NSNotificationCenter defaultCenter
         addObserver:self                        
         selector:@selector(keyboardDidShow:)    
         name:UIKeyboardDidShowNotification      
         object:nil];

      //向系統註冊,請系統將 keyboardDidHide: 的訊息送過來給我 (self)    
      [[NSNotificationCenter defaultCenter
         addObserver:self 
         selector:@selector(keyboardDidHide:) 
         name:UIKeyboardDidHideNotification 
         object:Nil];    
  }

  // textFieldDelegate method
  // 任何一個 TextField 開始被編輯
  -(void) textFieldDidBeginEditing:(UITextField *) textFieldView
  {    
      currentTextField = textFieldView;    
  }

  // textFieldDelegate method
  // TextField 結束編輯。當 user 按了鍵盤上的 Return
  -(BOOL) textFieldShouldReturn:(UITextField * ) textFieldView{
      [textFieldView resignFirstResponder];
      return YES;
  }


  // 當鍵盤顯示在桌面上,調整 scrollView 的外觀高度,使他不會被螢幕鍵盤擋住
  -(void)keyboardDidShow:(NSNotification *) notification{
    
      if(keyboardIsShown) return;
    
      // 取得 keyboard 的尺寸
      NSDictionary * info = [notification userInfo];
      NSValue *aValue=[info objectForKey:UIKeyboardFrameEndUserInfoKey];    
      CGRect keyboardRect = [self.view convertRect:[aValue CGRectValue] fromView:nil];
    
      // resize the scroll view (with keyboard)
      CGRect viewFrame = [self.scrollView frame];
      viewFrame.size.height = viewFrame.size.height - keyboardRect.size.height
      self.scrollView.frame = viewFrame;
    
      //接下來呼叫 scrollView method scrollRectToVisible textField 捲上來到可以被看見的位置
      [self.scrollView scrollRectToVisible:[currentTextField frame] animated:YES];
      keyboardIsShown = YES;    
  }


  // 當鍵盤關閉
  -(void) keyboardDidHide:(NSNotification *) notification{
      //取得鍵盤尺寸
      NSDictionary * info = [notification userInfo];
      NSValue *aValue=[info objectForKey:UIKeyboardFrameEndUserInfoKey];    
      CGRect keyboardRect = [self.view convertRect:[aValue CGRectValue] fromView:nil];
    
      // myScrollView 的尺寸改回原來的狀態
      CGRect viewFrame = [self.scrollView frame];
      viewFrame.size.height += keyboardRect.size.height;
      self.scrollView.frame = viewFrame;    
      [self.scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
      keyboardIsShown = NO;  
    }

  //當自己要被關閉,註銷之前的申請,讓系統不要再送訊息過來
  -(void) viewWillDisappear:(BOOL)animated{
      //remove the notifications for keyboard
      [[NSNotificationCenter defaultCenter]
       removeObserver:self
       name:UIKeyboardWillShowNotification
       object:nil];
      
      [[NSNotificationCenter defaultCenter]
       removeObserver:self
       name:UIKeyboardWillHideNotification
       object:nil];    
    
      [super viewWillDisappear:animated];
  }

  @end



沒有留言: