2012年3月12日 星期一

移除iOS虛擬鍵盤上的下ㄧ個與上一個按鈕

在iOS上需要輸入資訊的時候,會自動跳出一個虛擬鍵盤。鍵盤上方會有一排按鈕:上一個  / 下 一個 / 完成。有時候很有用,但是有時候很惱人。如果你的App會因為未知的下一個導致行為亂跳的會可能會很麻煩。原本覺得應該是模擬鍵盤的Tab,但是收keydown的時候並沒有任何事件發生,所以大概是iOS自己做掉了。因此要解決亂跳的問題就只能把這一排按鈕幹掉。

首先必須知道鍵盤出現的時間點,在 viewDidLoad 的函式中加入:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

這樣就可以註冊一個observer,在鍵盤要出現的時候會呼叫我們定義的keyboardWillShow method:
- (void)keyboardWillShow:(NSNotification *)note {
    [self performSelector:@selector(removeBar) withObject:nil afterDelay:0];
}
這邊需要一個短暫的delay再去呼叫removeBar,因為在收到的當下鍵盤的view還沒實際出現。不過這樣一來就有可能執行removeBar的時候鍵盤其實還沒出現(我反覆測試了很多次,都還沒遇到有失敗的case)。 實際上真正移除的code如下,先找到非UI-Window的keyboardWindow,之後在從keyboard的subviews裡面找到鍵盤上方的按鈕subview:
- (void)removeBar {
    // Locate non-UIWindow.
    UIWindow *keyboardWindow = nil;
    for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
        if (![[testWindow class] isEqual:[UIWindow class]]) {
            keyboardWindow = testWindow;
            break;
        }
    }

    // Locate UIWebFormView.
    for (UIView *possibleFormView in [keyboardWindow subviews]) {       
        // iOS 5 sticks the UIWebFormView inside a UIPeripheralHostView.
        if ([[possibleFormView description] rangeOfString:@"UIPeripheralHostView"].location != NSNotFound) {
            for (UIView *subviewWhichIsPossibleFormView in [possibleFormView subviews]) {
                if ([[subviewWhichIsPossibleFormView description] rangeOfString:@"UIWebFormAccessory"].location != NSNotFound) {
                    [subviewWhichIsPossibleFormView removeFromSuperview];
                }
            }
        }
    }
}
此文參考:A one stop blog for iPhone Application Development

2012年3月1日 星期四

iScroll.js的scroll不順怎麼辦?


如果有寫WebApp的人一定會遇到要對content做scroll的需求。這時候你通常有幾種選擇:
  1. 把不需要scroll的DOM元件的CSS position屬性設定為fixed,然後依靠device上預設的web browser的scroll功能。這個功能絕對行得通,但是如果是在iOS上的話,你一定會覺得為什麼這個scroll特別黏?就是一做fling的動作,就是沒有其他原生App的scroll的流暢。其實你試試iOS上的Safari,的確就是這個行為沒錯,感覺是特別設計有什麼特殊用意並不清楚。但是很明顯的這個方法對於要求原生App的UI體驗是不夠的。
  2. iOS5之後的WebBrower有支援一個特別的overflow值,也就是 overflow:scroll 。設定這個之後,超過容器空間的iOS會自動套用原生的scroll功能。也行得通,如果你不打算支援iOS4的話。
  3. 為了克服以上兩個問題,我的選擇是使用iScroll.js,一個Open Source的JavaScript library。很強大,把scroll模擬的很好,而且也會自動產生捲軸。大致上的原理是使用Timer(window.setTimeout)來模擬scroll,也有支援momentum。但是我一直很疑惑的是怎麼在實際的iOS裝置上的scroll animation的frame rate 竟然或是這麼低呢?好吧,重點就在他用了setTimeout! setTimeout! setTimeout! 所以frame rate低是很正常的啊,大概連15fps都不到吧。這時候想說如果用CSS transition(感謝我曾經在之前的公司present過CSS3)的話應該會順暢很多吧。畢竟transition是native code在做animation,而且適當的trick(就是設定一個完全沒作用的3D Transform)還可以啓動硬體加速,FPS一定可以提升到30以上。於是我打開iScroll的source code:
     // Constructor
     iScroll = function (el, options) {
      var that = this,
       doc = document,
       i;
    
      that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
      that.wrapper.style.overflow = 'hidden';
      that.scroller = that.wrapper.children[0];
    
      // Default options
      that.options = {
       hScroll: true,
       vScroll: true,
       x: 0,
       y: 0,
       bounce: true,
       bounceLock: false,
       momentum: true,
       lockDirection: true,
       useTransform: true,
       useTransition: false,
       topOffset: 0,
       checkDOMChanges: false,  // Experimental
    
       // Scrollbar
       hScrollbar: true,
       vScrollbar: true,
       fixedScrollbar: isAndroid,
       hideScrollbar: isIDevice,
       fadeScrollbar: isIDevice && has3d,
       scrollbarClass: '',
    
       // Zoom
       zoom: false,
       zoomMin: 1,
       zoomMax: 4,
       doubleTapZoom: 2,
       wheelAction: 'scroll',
    
       // Snap
       snap: false,
       snapThreshold: 1,
    
       // Events
       onRefresh: null,
                onBeforeScrollStart: function (e) { e.preventDefault(); },
       onScrollStart: null,
       onBeforeScrollMove: null,
       onScrollMove: null,
       onBeforeScrollEnd: null,
       onScrollEnd: null,
       onTouchEnd: null,
       onDestroy: null,
       onZoomStart: null,
       onZoom: null,
       onZoomEnd: null
      };
    
    你看到第22行了嗎?useTransition: false,哇,太令人欣慰了。我什麼都不用改耶。只要把它改成 useTransition: true 就好了耶(但還是要記得把要scroll的DOM加上null 3D transform)。果然一改完就很順。省了我很多時間:)
Related Posts Plugin for WordPress, Blogger...