- 2011-11-09 (水) 18:59
- JavaScript | SmartPhone
ちょこちょこまとめてみた。
まず
Androidには、window.orientation 及び window.onorientationchange を持ってるのと持ってないのがあるらしいので、
$(window).data('orientation', (function(){ if(typeof window.orientation === 'number'){ return Math.abs(window.orientation); }else{ return (window.innerWidth < window.innerHeight) ? 0 : 90; } })());こんな感じで orientation を window の data として保持しておく。 同じように onorientationchange の方もラッパーを作っておく。
orientationChange = function(handler){ $window = $(window); var has_orientation = typeof window.orientation === 'number'; var EVENT_TYPE = has_orientation ? 'orientationchange' : 'resize';</p> <p>({ check : function(){ if($window.data('orient_width') == window.innerWidth){ return false; }else{ $window.data({ orientation : this.getOrientation(), orient_width : window.innerWidth, orient_height : window.innerHeight }); return true; } }, getOrientation : function(){ if(has_orientation){ return Math.abs(window.orientation); }else{ return (window.innerWidth < window.innerHeight) ? 0 : 90; } }, exec : function(){ var _self = this;</p> <pre><code> $window.data({ orientation : _self.getOrientation(), orient_width : window.innerWidth, orient_height : window.innerHeight }); $window.bind(EVENT_TYPE, function(e){ $window.data('orientation', _self.getOrientation()); if(v.UA.isAndroid &amp;&amp; !has_orientation){ (function(){ if(!_self.check()){ setTimeout(arguments.callee, 100); } else{ handler(); } })(); }else{ $window.data({ orient_width : window.innerWidth, orient_height : window.innerHeight }); handler(); } }); handler(); } </code></pre> <p>}).exec(); }らしい、っていうのは実機で遭遇したわけではないため。
Android だった場合全部 resize イベントに回そうかとも考えたけど、 やっぱり orientation を持ってるものはそっちで処理するようにした。
で
上記の状態で、イベントハンドラに要素をセンタリングする処理を渡したところ、 画面の向きを変えてもハンドラが実行されていないようだったので調べてみた。
ハンドラの中で、window.innerWidth や window.innerHeight を使ってる場合、 orientation の切り替え直後は、
landscape時:portrait時の window.innerWidth/Height portrait時:landcaape時の window.innerWidth/Height
が返ってきてた。 setTimeout 使って監視してみると、100msほど遅れて切り替わる感じ。
別に動的に必要なものでもないので、読み込み時に保持してしまおう。
毎回 setTimeout 使うのもめんどくさいので。 というわけで、
device = { innerWidth : (function(){ var portrait,landscape; var innerHeight = (isIOS) ? screen.height : window.outerHeight/window.devicePixelRatio|0; if($(window).data('orientation') === 0){ portrait = window.innerWidth; landscape = innerHeight; }else{ portrait = innerHeight; landscape = window.innerWidth; }</p> <pre><code>return { portrait : portrait, landscape : landscape }; </code></pre> <p>})(), innerHeight : (function(){ var portrait,landscape; var bar = (function(){ if(isIOS){ return ($(window).data('orientation')===0) ? 52 : 64; }else{ return (window.outerHeight/window.devicePixelRatio) - window.innerHeight; } })(); if($(window).data('orientation')===0){ portrait = window.innerHeight; landscape = window.innerWidth - bar; }else{ portrait = window.innerWidth - bar; landscape = window.innerHeight; } return { portrait : portrait, landscape : landscape }; })() }window.outerHeight から取ろうとするとなぜかデバイスのY軸方向のピクセル数を返しやがりますので、 window.outerHeight / window.devicePixelRatio と、pixelRatio の倍率を考慮してやると、欲しい値になる。
outerHeight から innerHeight を引くとアドレスバーの高さが取れるので、 JSが読み込まれた時点での端末の向きを見て、window.innerWidth/Heightから、 縦/横向きの時の innerWidth/Height をそれぞれ計算して変数に入れておく。
iPhoneの場合は、ツールバーが portrait時:44px landscape時:32px なので、これにステータスバーの20pxを足した固定値でOK。 outerHeight も window.outerHeight もしくは screen.height でOK。 (そもそもこの処理も必要ないけども)
これで orientationchange の時にこっちの意図通り変化してくれない window.innerWidth/Height を見に行かなくても、 要素のセンタリングができるようになった。
何か忘れてる
持たざる者は?
window.onorientationchange を持っていない場合、 window.onresize で、window.innerWidth と window.innerHeight を比べて端末の向きを判別するので、 おとなしく状態監視をしたほうが無難な気がする。 $(window) に data として持たせると、複数要素に指定したときにうまく動かなさそうなので、 各要素ごとに持つとかそんな感じ。
- Newer: 【Android】【ActionScript】FlashPlayer11で追加されたJSONがas3corelibとバッティングする
- Older: 【iPhone】iOS5で追加になったもろもろ
Comments:0
Trackbacks:0
- Trackback URL for this entry
- http://unolabo.boo.jp/archives/2011/11/09-orientationchange%e3%81%ae%e6%8c%99%e5%8b%95%e5%88%b6%e5%be%a1.html/trackback
- Listed below are links to weblogs that reference
- 【Android】orientationchangeの挙動制御 from うのらぼ。