2013年11月18日月曜日

Android 7 inch 用にスケールアップする場合の文字サイズ

スマホのレイアウトをそのまま 7 inch で表示すると多少スカスカになります。
レイアウトを最適化するほどではない場合、全体的なサイズを大きくして調整することがよくあります。
こういうときは、だいたい1.5倍にするといい感じになります。

文字サイズの場合は、1.5倍にすると大きすぎるので、 デフォルトの文字サイズに対応する私なりの値をメモっておきます。

res/values/dimens.xml 22sp 18sp 14sp

res/values-sw600dp/dimens.xml 30sp 25sp 20sp

res/values/styles.xml




2013年11月14日木曜日

KitKat (Android 4.4) の UI について

Android 4.4 KitKat 冬コミ原稿リレーの 11/14 分です。

Android 4.4 KitKat の API の内、User Interface に関わる部分を取り上げます。


■ Immersive full-screen mode

昔々、2.x まではフルスクリーンモードというものがありました。このときはホームキーやバックキーがハードキー(ハードボタン)だったため、ステータスバーが隠れ、画面全体がアプリの領域になるというものでした。

3.x になると、画面下部がナビゲーションバーというものになり、ステータスバーの情報はナビゲーションバーの右側に、ホームキーやバックキーは左側に移動しました。 このナビゲーションバーは、これまでのフルスクリーンモードを指定しても表示されたままでした。

4.0 ICS (API Level 14) になると、スマホにもナビゲーションバーが導入されました。
ハードキーよ、さようなら。
ナビゲーションバーを暗くしたり、インタラクションがない間(動画を見てるなど)非表示にすることができるようになりました。
  • SYSTEM_UI_FLAG_VISIBLE (0x00000000)
  • SYSTEM_UI_FLAG_LOW_PROFILE (0x00000001)
    ナビゲーションバーを暗くする(オーバーフローメニューを表示するとなぜかクリアされる。Action Item のクリックではクリアされない)
  • SYSTEM_UI_FLAG_HIDE_NAVIGATION (0x00000002)
    インタラクションがない間ナビゲーションバーを非表示にする (ちなみに、SYSTEM_UI_FLAG_LOW_PROFILE と SYSTEM_UI_FLAG_HIDE_NAVIGATION を両方指定すると、ナビゲーションバーは非表示になり、インタラクションがあって表示された瞬間は暗くなっていて、すぐに明るくなる)

4.1 Jelly Bean (API Level 16) では、ナビゲーションバーやステータスバー(これらを合わせてシステムバーとドキュメントでは書かれている)の見た目を制御するためのフラグがいくつか追加されました。
  • SYSTEM_UI_FLAG_FULLSCREEN (0x00000004)
    ステータスバーを非表示にする
    SYSTEM_UI_FLAG_LOW_PROFILE や SYSTEM_UI_FLAG_HIDE_NAVIGATION と組み合わせて指定すると、ナビゲーションバーが表示されるタイミングでステータスバーも表示される
    単体で指定した場合はインタラクションがあっても非表示のまま
  • SYSTEM_UI_FLAG_LAYOUT_STABLE (0x00000100)
  • SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION (0x00000200)
    ナビゲーションバーが非表示であるかのようにビューをレイアウトする
  • SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN (0x00000400)
    ステータスバーが非表示であるかのようにビューをレイアウトする
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN だけを指定した状態


4.4 KitKat (API Level 19) では、インタラクションがあってもシステムバーを非表示のままにできるようになりました。
  • SYSTEM_UI_FLAG_IMMERSIVE (0x00000800)
  • SYSTEM_UI_FLAG_IMMERSIVE_STICKY (0x00001000)
* immersive は没入とか没頭という意味です。

SYSTEM_UI_FLAG_HIDE_NAVIGATION フラグや SYSTEM_UI_FLAG_FULLSCREEN フラグと組み合わせて setSystemUiVisibility() に指定します。
これらを指定すると、ステータスバー(SYSTEM_UI_FLAG_FULLSCREEN)やナビゲーションバー(SYSTEM_UI_FLAG_HIDE_NAVIGATION)が非表示になり、画面全体をアプリの領域にできます。
システムバーを表示するには、「システムバーが表示されるべき領域から内側に向かってフリック」します。
ユーザーがこの操作を行うと、SYSTEM_UI_FLAG_HIDE_NAVIGATION フラグと SYSTEM_UI_FLAG_FULLSCREEN フラグがクリアされるので、全画面表示ではなくなります。
SYSTEM_UI_FLAG_IMMERSIVE を指定した場合は、そのまま全画面表示が解除されたままになり、SYSTEM_UI_FLAG_IMMERSIVE_STICKY を指定すると数秒後に再び全画面表示に戻ります。

なぜか、オーバーフローメニューを表示すると immersive mode がクリアされてしまいます。。。


SYSTEM_UI_FLAG_IMMERSIVE | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION

わーい。全画面だー。

SYSTEM_UI_FLAG_IMMERSIVE_STICKY | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION で「システムバーが表示されるべき領域から内側に向かってフリック」したとき

View の上に半透明で表示されます

初めて全画面表示したときは、こんなポップアップが自動で出ました。




■ Translucent system bars

システムバーを透明にすることができるようになりました。

システムバーが透明のテーマが用意されています。
  • Theme.Holo.NoActionBar.TranslucentDecor
  • Theme.Holo.Light.NoActionBar.TranslucentDecor
ActionBar とは併用できないんですかね。。。

Theme.Holo.NoActionBar.TranslucentDecor

黒わからん。。。w

Theme.Holo.Light.NoActionBar.TranslucentDecor
1592 ステータスバーを透明にする属性が android:windowTranslucentStatus
ナビゲーションバーを透明にする属性が android:windowTranslucentNavigation
です。

試しに ActionBar と併用してみました。 としたら、こうなりました。。。ひどいw


android:fitsSystemWindows="true" を指定すると、システムバー分のパディングがセットされます。 ただし、android:paddingXXX で指定したパディングが上書きされるので注意が必要。 ... 左右の padding もなくなってしまった。。。



■ Enhanced notification listener

API Level 18 で追加された NotificationListenerService が拡張されました。

Notification に新しく extras というフィールドが増えて、この Bundle 用のキーがいろいろ追加されました。 また、新しく actions というフィールドも増えました。このフィールドは Notification.Action の配列で、Notification.Builder の addAction() で格納されます。



■ Scenes and transitions

新しく android.transtion フレームワークが提供されるようになりました。

ユーザーインタフェースの異なる状態間のアニメーションを促進するためのものだそうです。 Scene.getSceneForLayout() を使って Scene を作ります。 レイアウトを切り替える領域の ViewGroup を第1引数に、切り替えるレイアウトを第2引数に、第3引数には Context を指定します。 あとは、TransitionManager.go() を呼べば、いい感じにアニメーションでレイアウトが切り替わります。 findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ViewGroup view = (ViewGroup) findViewById(android.R.id.content); Scene scene = Scene.getSceneForLayout(view, R.layout.scene2, MainActivity.this); TransitionManager.go(scene); } }); レイアウトを切り替える領域の ViewGroup を指定して TransitionManager.beginDelayedTransition() を呼ぶと、ViewGroup の子 View が変わったときに自動でいい感じにアニメーションしてくれます。 この方法だと Scene を作る必要はありません。

# やってみたけど、アニメーションしてくれない。。。 final ViewGroup view = (ViewGroup) findViewById(android.R.id.content); TransitionManager.beginDelayedTransition(view); findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { View inflate = LayoutInflater.from(MainActivity.this).inflate(R.layout.scene2, view, false); view.addView(inflate); } }); 特定のアニメーションを指定するには、Transition を継承したクラスのインスタンスを指定します。 指定されていないときは AutoTransition が利用されます。 Fade や ChangeBounds、Visibility などいくつかのクラスがあらかじめ用意されています。 Scene scene = Scene.getSceneForLayout(view, R.layout.scene2, MainActivity.this); TransitionManager.go(scene, new ChangeBounds()); res/transition/ に定義した XML ファイルに対して TransitionInflater.inflateTransition() を使うことでも Transition のインスタンスを作成することができます。 XML については TransitionManager のドキュメントの説明を読むのがいいです。



# 今のところ、これだ!という使い道がわかってません。。。w



明日は @checkela さんです!

2013年11月11日月曜日

ViewPager で Volley の NetworkImageView を使うときの注意点

ViewPager の子要素は、ページが変わったときにも onLayout() が呼ばれます。

整理すると、ページが切り替わると
・新しく生成されたページ(PagerAdapter の instantiateItem() が呼ばれるところ)では onLayout(true, ...) が呼ばれる
・現在の子要素全てで onLayout(false, ...) が呼ばれる


Volley の NetworkImageView (2013年11月11日)では、 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); loadImageIfNecessary(true); } のようになっています。

これだとページを切り替えるたびに画像の読み込みが実行されてしまいます。

changed が true のときだけにすれば、新しく生成されたときだけ実行されるようになります。 @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (changed) { loadImageIfNecessary(true); } }