Window Shade 
我手上的Samsung Galaxy S3的作業系統是Android 4.0.4。
當我收到facebook/google+/…等程式通知的時候,最上面那條bar會出現對應的圖示。
這時候可以透過將bar「滑下來」的動作拉出一個UI,裡面會有
快速設定 
通知項目詳細列表 
 
這個UX,Google把它稱為Window shade 
神奇的地方在於當你在拉下或拉上面板的同時,
快速設定與通知項目是會先「掉下來」到底端,
到了項目的頂端出現之後才會黏在頂部。
(相信我你沒有特別注意這件事情,而且用久了會覺得理所當然)
GAIA也有notification panel 
Firefox OS的UI – GAIA 裡面也有定義功能列以及通知面板這件事,
這個功能正在開發中。
有一天我們收到某個contributor提交的pull request:
Gaia pull request#1898 
節錄重要的修改如下:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
  onTouchMove :  function  ut_onTouchMove ( touch )  { 
     var  screenHeight  =  this . overlay . getBoundingClientRect (). height , 
         gripBarHeight  =  this . gripBar . getBoundingClientRect (). height , 
         dy  =  - ( this . startY  -  touch . pageY ), 
         newHeight ; 
     if  ( this . shown ) 
       dy  +=  screenHeight ; 
     dy  =  Math . min ( screenHeight ,  dy ); 
 
     if  ( dy  >  gripBarHeight )  { 
       var  quickSettingsHeight  =  this . quickSettings . getBoundingClientRect (). height ; 
 
       if  ( dy  <  quickSettingsHeight  +  gripBarHeight )  { 
         newHeight  =  screenHeight  -  quickSettingsHeight  -  gripBarHeight ; 
       }  else  { 
         newHeight  =  screenHeight  -  dy ; 
       } 
       this . quickSettings . style . MozTransition  =  '' ; 
       this . quickSettings . style . MozTransform  =  'translateY('  +  newHeight  +  'px)' ; 
     } 
 
     var  style  =  this . overlay . style ; 
     style . MozTransition  =  '' ; 
     style . MozTransform  =  'translateY('  +  dy  +  'px)' ; 
   }, 
   //....skiped... 
   show :  function  ut_show ( dy )  { 
     var  alreadyShown  =  this . shown , 
         trayStyle  =  this . overlay . style , 
         quickSettingsStyle  =  this . quickSettings . style ; 
 
     trayStyle . MozTransition  =  '-moz-transform 0.2s linear' ; 
     trayStyle . MozTransform  =  'translateY(100%)' ; 
 
     quickSettingsStyle . MozTransition  =  '-moz-transform 0.2s linear' ; 
     quickSettingsStyle . MozTransform  =  'translateY(0px)' ; 
 
     this . shown  =  true ; 
     this . screen . classList . add ( 'utility-tray' ); 
 
     if  ( ! alreadyShown )  { 
       var  evt  =  document . createEvent ( 'CustomEvent' ); 
       evt . initCustomEvent ( 'utilitytrayshow' ,  true ,  true ,  null ); 
       window . dispatchEvent ( evt ); 
     } 
   } 
 
 
原作者提到他做這件事是要讓quick-setting更快的出現。
這段code也已經被merge了。
不過就在昨天同事發現了一個關於功能列的issue 
於是我開始看發生了什麼事。然後上面那兩個function耗費了我一個下午….XD
@colinfrei其實做了一件非常有趣但是很難從code裡面看出端倪的事情。
甚至也很難用語言來描述,不過我想試著說明發生了什麼事,怎麼做到的。
簡單的說,他利用兩個「不同」區塊的CSS3的Transition「同步化」來實現剛剛所提的Window Shade的行為。
CSS: Transition 
參閱MDN: transition 
CSS: Transform 
參閱MDN: transform 
真相其實是: 
utility-tray是一個絕對定位的div,平常位置定在螢幕上方-moz-calc(100% – UTILITY_TRAY_HEIGHT)。 
當你開始Touch的時候,根據你的移動距離計算translateY,使它產生位移
 你可以把-moz-transform: translateY(px)當成是top: px在CSS3的新招。
 它提供了更快速的rendering — 當你想利用-moz-transition: -moz-transform來做位移動畫的時候。
 這件事情可以另外寫一篇文章來說(挖洞的意味)。
 
當你放開拉bar的時候而且如果已經超過「要讓通知面板掉下來的合法距離」:
設定一個MozTransition給utility-tray-overlay 
再設定一個MozTransition給quick-setting 
 
 
 
4.讓utility-tray整個以某個定速掉下來到螢幕底端 + 讓quick-setting以同樣的定速往上移動到utility-tray的開端
  = 於是就造成了quick-setting似乎黏在通知列下方不動但整個面板是往下掉的假象!
the story continues 
不過可惜的是似乎沒有考慮到當通知面板要滑上去的時候,
「有物件的部份也應該留在頂端直到被拉bar撞到一起彈上去」這件事
於是我也仿造這個作法另外送了一個pull request
GAIA pull request#2181 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
  case  'transitionend' : 
     if  ( ! this . shown )  { 
       this . screen . classList . remove ( 'utility-tray' ); 
 
       var  overlayStyle  =  this . overlay ; 
       var  firstShownStyle  =  this . firstShowStyle ; 
       firstShownStyle . MozTransition  =  '' ; 
 
       if  ( this . phase2hide )  { 
         firstShownStyle . MozTransition  =  '-moz-transform 0.2s linear' ; 
         firstShownStyle . MozTransform  = 
           'translateY('  +  this . firstShownPosition  +  'px)' ; 
         overlayStyle . MozTransition  =  '-moz-transform 0.2s linear' ; 
         overlayStyle . MozTransform  =  'translateY(0)' ; 
 
         // Check the transition event is triggered at firstShown. 
         // If so, turn off the flag which represent for 
         // 'The overlay has already reached the bottom of quick-setting' 
         if  ( evt . target  ==  this . firstShown ) 
           this . phase2hide  =  false ; 
       }  else  { 
         // Reset position of this.firstShown 
         this . firstShown . style . MozTransition  =  '' ; 
         this . firstShown . style . MozTransform  =  'translateY(0)' ; 
       } 
     } 
     break ; 
 
 
利用transitionend event callback,透過連續兩次的Transition來:
讓utility-tray先定速往上移動/讓quick-setting定速往下移動到底端。 
等到utility-tray的transition結束時,會收到transitionend的事件。
 這時候再讓utility-tray進行第二次transition…而目的地就是螢幕頂端。
 同時quick-setting就不再動作了,讓它跟著utility-tray一起被往上卷走。 
 
transitionend 
參閱MDN: transitionend 
the end? 
其實UX還沒有定義這個行為,所以pull request本身沒有被接受。
不過…I did learn something from these codes:)