アプリ開発・端末毎の解像度の違いを吸収する方法 android bazaar and conference...
TRANSCRIPT
アプリ開発端末毎の解像度の違いを吸収する方法
プロの方はご遠慮ください !
株式会社 PM9 野田邦昌
自己紹介
PM9 雑用係 野田邦昌
たまたま「 OpenWnn フリック ( 入力対応版 ) 」というものを開発
先日、おっさんの仲間入りをはたしました。誕生日が来たとかということではなく、
ある意味悟りの境地というか座右の銘は 「押してだめなら引いてみろ」
自己紹介「会社名の由来は?」って良く聞かれます。よっぽど「あやしいん」でしょうか。
「株式会社 PM9 」に対する一般的なイメージ
ナイスミドルな方は、「え? 11PM 」となるらしい。
※ 11PM( テレビの深夜番組 巨泉さん とか 欽也さん出演 )
ナイスミドルで、なおかつ常識的な方は…心の声 : 「まさか、そんな露骨なわけない」表の声 : 「 PM ( プロマネ ) が 9 人いらっしゃると !! 」心の声 : 「けっ ハッタリが ! 」となる傾向にあります
自己紹介
フレッシュな方は…
「やっぱ、あれ系ですか ? ♡ 僕もやってみたいです」
たぶん、ご想像されているものとは違うと思います。やってもらってもかまいませんが。というか、むしろありがたい。
俺の開発スタイル (Android も含めて )
気持ちの良いアプリを 気持ちよく作ってますか? サクッと !!
(PM9) 野田の場合 一日の過ごし方
人に言われて何かの
資料を一生懸命作って
いる55%
人に声を掛けられて身動きが
取れなくなっている20%
コーディング5%
何で動かないのか?と夜中に色々試行錯誤
20%
結論
気持ちよく作るって言うのは、ちょっとどうやって良いのか分からないけれども、
気持ちの良いアプリ ( を作る ) ってのは、どうにかなるのかもしれない。
たぶん !!
結論
斬新なアイデアが、 1 つあれば十分
もちろん、斬新すぎて理解不能なのはちょっと
小奇麗であれば十分
違和感を感じる部分をコツコツと直していく … ここ結構重要
アイデアはお客さんがくれる
やっと本題 -- アプリケーション開発における様々な端末特性の考慮
端末 ( 機種 ) 毎に特性が違います。
・ OS バージョン・画面サイズ・画面密度・色々なセンサーなどのデバイスの有無とか特性
放って置いても、自動的にやってくれる…というわけにはいかないときがある。
開発者としては、一応勉強してアプリを作っているつもりなんだけれどもマーケットのコメント欄は…
普段からでも「へーそんな使い方できるんだ~」って開発者でさえ気づかないような使い方でコメントされるわけですが、
開発者としては、一応勉強してアプリを作っているつもりなんだけれども
マーケットのコメント欄は…
「~ ( 機種名 ) で動きません。」「 OS アップデートしたら、落ちるようになりました。」「端っこの方が見えません。」
× 開発者としては、思っても見なかった非難にさらされた○ 有り難い助言をいただいた
開発者は何をしているのだ?
開発者のみなさん、結構まじめです。Androidエミュレーター (AVD ってやつ ) を使ってテスト
手元にある実機でテスト
お約束のテストは当然行います。
開発者は何をしているの?
でも、実機だと何故かエラーが
「マニュアル見りゃ分かるだろうがー」となりますが、いえ、わかりません。
特にセンサーのようなデバイスまわりの API情報が足りてません。
全ての種類の端末で試すのは無理
情報を共有する手段を持つ法則性を見つけて、計画的に問題を回避
ちょっと、一言端末特性情報共有サービスのご提案(1) 「端末特性テスト」アプリというものを Android マーケットで配布。
(2) Android アプリ開発者等を含む Androidユーザーはこのアプリをダウンロードして実行する。
すると、クラウド上のサーバーに下記の情報がアップロードされる。
端末機種名OS バージョン各入出力デバイスの有無とかスペックとかROM を焼いてたらその情報も
API を使ってデバイスにアクセスした場合、どんなことが起るのか、どんな値を得ることができるのか
( これが一番重要 )
※ どの API を試すのかは、 Android アプリ開発者からのリクエストを元に
端末特性情報共有サービスのご提案
(3) アップロードされた各端末の特性情報は、 誰でも参照可能
Android アプリ開発者は、これを見てへんな動きをする等の原因が掴めるようになる。
奇特な開発者は、誰でも簡単に統一した仕様でデバイスにアクセスできるラッパー用のライブラリを作って配布する。
商品として売っても良し。
メーカーさんとしては、ちゃんと仕様どおりに作っておられるわけだけれども、他のメーカーさんの端末特性を見ることで新しい発見とかあるでしょ?
まずは、Android コーディングのおさらい - プロジェクトHogeHoge /
AndroidManifest.xmlsrc /
com.fuga.hogehoge /HogeHogeActivity.java … 画面表示
res /layout /
hogehoge.xml … UI定義 ( レイアウト + UI 部品 )
drawable /icon.pnghoge.png … 画像等
values /strings.xml … 文字列定数
gen /com.fuga.hogehoge /
R.java … ビルドすると自動生成される
Android コーディングのおさらい- プロジェクト
R.java って?
ビルドすると自動生成される。
リソース ID と リソースインデックス の関係が記述されている。
リソース ID: res ディレクトリ下のパス名 + リソースの各項目の id属性から決定される。 android:id=“@+id/button_1” プログラムからは、 R.id.button_1 で参照
リソースインデックス : 全てのリソースに自動的に通し番号が割り振られる。
おさらい - UI の構成要素
ViewGroup ( ようするにレイアウト )例 ) LinerLayout とか TableLayout とか子 View の配置方法などを指定して、 View の追加ができる ViewGroup を子供として配置可能
View (UI 部品のこと )例 ) Button とか EditText とか
LayoutParams ( レイアウトの為のパラメータ )
View の配置のしかたを指定
※ 感覚的には HTML に近い
おさらい - UI定義XML によるレイアウト定義
HogeHoge / res / layout / hogehoge.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=
http://schemas.android.com/apk/res/android android:id=“@+id/hoge_id” android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<Button android:id="@+id/button_2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Button 2"/>
</LinearLayout>
おさらい - UI定義 XML による定義
Java からは、こんな感じで利用する。
public class HogeHogeActivity exteds Activity {public void onCreate(
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.hogehoge);
}}
HogeHoge/res/layout/hogehoge.xml に基づいて画面が描画される。
おさらい - UI定義 Java から定義レイアウト XML を用いず、動的に UI を生成
public class HogeHogeActivity extends Activity {public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
LinearLayout layoutHogehoge = new LinearLayout(this);setContentView(layoutHogehoge);
Button button1 = new Button(this);button1.setText("Button");layoutHogehoge.addView( button1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));}
}
おさらい - レイアウト用 XML をJava から読み込んで弄くる(1) hogehoge.xml(2) fugafuga.xml
setContentView(R.layout.hogehoge);
LinearLayout layoutHogehoge = (LinearLayout)findViewById(R.id.hoge_id);
LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layoutFugafuga = (LinearLayout)inflater.inflate(R.layout.fugafuga, null);
layoutHogehoge.addView(layoutFugafuga);
いよいよ端末特性 Android における「画面サイズ」の分類
small ~ 3.7 inchぐらいnormal 3.x ~ 4.x inch ぐらいlarge 4 ~ 7 inch ぐらいxlarge 7 inchi 以上
Android における「画面密度」の分類
dpi = Dot per inch一般的な CRT 、 LCD は、 72 ~ 96dpi印刷物は 300 ~ 350dpi以上のピクセル密度となっている
ldpi低密度 (実測値 :100 ~ 140dpi)システム上は 120dpi として扱う
mdpi中密度 (実測値 : 140 ~ 180dpi)システム上は 160dpi として扱う
hdpi高密度 (実測値 : 190 ~ 250dpi)システム上は 240dpi として扱う
xhdpiシステム上は 320dpi として扱う
Android における「アスペクト比」の分類
アスペクト比 ( 画面の縦横比 ) が4:3 ~ 16:9 の間におさまっているか?
not-long おさまっている
long おさまっていない
Android における「オリエンテーション」の分類
画面が縦向き /横向きの状態
port 縦向き
land 横向き
Android における長さの単位 (1)
px -- いわずと知れたピクセル単位 (pixel)
dp もしくは dip
device-independent pixel
( 端末非依存ピクセル )
※ dpi じゃなくて dip
mdpi(160dpi) の機種の物理的なピクセル幅 (px) を基準とした単位
Android における長さの単位(1)dp 続き…
中解像度 mdip(160dpi) の機種 (HT-03A等 )上に32px x 32px のサイズの「箱」を描いた
物差しではかったらどれも大体約 5mm x 5mmぐらいの「箱」が描かていることになる。
中解像度 mdip(160dpi) の機種 (HT-03A等 )上に32dip x 32dip のサイズの「箱」を描いた
高解像度 hdpi(240dpi) の機種 (Xperia arc等 )上に32dip x 32dip のサイズの「箱」を描いた
Android における長さの単位(2)
sp もしくは sip Scale-independent Pixels (倍率非依存ピクセル )
dp に似ているが標準文字サイズという情報も考慮して調整してくれるという何か良い具合な単位
フォントサイズの指定に使うお約束※ ポイント指定じゃないのね
Android における長さの単位(2)
pt -- 言わずと知れたポイント = 1/72 インチ
in -- インチ
mm -- ミリメートル
<resource><dimen name="hogehoge_text_size">12sp</dimen><dimen name="hogehoge_icon_sp">32dp</dimen>
</resource>
とやっておいて、名前で指定できちゃいます。
<TextViewandroid:textSize="@dimen/hogehoge_text_size"...
/>
長さに名前を付けることができます
長さに名前を付けることができます
ちなみに、 Java からもアクセスできちゃいます。
float txSize = Resources.getDimension(
R.dimen.hogehoge_text_size);
レイアウト (1)
基本は、 res/layout 下にレイアウト用 XML を置く
HogeHoge / res / layout / hogehoge.xml
ところで、魔法のようなことが…
HogeHoge / reslayout
hogehoge.xmllayout-xlarge
hogehoge.xml <= ここにレイアウト用 XML を置くと…
画面サイズが 7inch( つまり xlarge) のタブレットだとこちらのレイアウトが…
レイアウト (2)
されにさらに、
HogeHoge / res /layout /
hogehoge.xmllayout-xlarge /
hogehoge.xmllayout-xlarge-land /
hogehoge.xml <= ここにレイアウト用 XML を
置くと横向きのときのレイアウトが…
レイアウト (3)
こういう表がありまして、こちらを自由に組み合わせて作ることができます。
修飾子 値 備考
MCC, MNC mcc440-mnc10
mcc440-mnc20
mcc440-mnc70
DoCoMo
Softbank
au
言語と地域 en-rUS
fr-rFR
etc
画面サイズ small
normal
large
xlarge
レイアウト (3)画面アスペクト long
notlong
画面オリエンテーション
port
land
ドックモード car
desk
ナイトモード night
notnight
画面ピクセル密度 (dpi)
ldpi
mdpi
hdpi
nodpi
システムバージョン (API レベル )
v3
v4
…
レイアウト (3)タッチ画面タイプ notouch
stylus
finger
キーボードの使用状態 keysexposed
keyssoft
keyshidden
主なテキスト入力方式 nokeys
qwerty
12key
ナビゲーションキーの使用
navexposed
navhidden
主な非タッチナビゲーション方式
nonav
dpad
trackball
wheel
レイアウト (4)
例 )layout-xlarge-xhdpi-long-port-querty-v12
特大スクリーン、 320dpi 、細長画面、縦向き、 Qwertyキーボード搭載、 Android 3.1 の画面レイアウト
ルール :項目がもっとも多くマッチしたものを採用
レイアウト (5)
android:layout_width 、android:layout_heigth等
wrap_content( その UI 部品を表示するための最小のサイズ )
fill_parent(親要素の幅 /高さに合わせて最大限の領域を使うサイズ )
を使う !!
android:padding ~、 android:textSize等dp や sp
を使う !!
画像リソースについて -- オートスケールと言う考え方
お約束のように res/drawable 下に画像ファイルを置いておく
Android は、端末のピクセル密度に合わせて、かってに画像を拡大・縮小してサイズを調整してくれる。
※ オートスケールにまかせると、画像がぼやけることがあります。
例 ) Xperia(初代 ) が出たばかりのころの OpenWnn フリック
キートップの画像の hdpi 対応をサボったため、キーボードが「ゆうれいみたい」とのお言葉をいただきました。
画像リソースについて -- プレスケールres /
drawable /hogehoge.png
drawable-hdpi /hogehoge.png
drawable-mdpi /hogehoge.png
drawable-ldpi /hogehoge.png
レイアウトの場合と同じ考え方で、画面の性質に合わせて魔法のように自動的に最適な画像が選ばれます。
画像リソースについて -- プレスケール
Tips: ( いくぶん受け売りです )
予想以上のスピードでハードウェアは進化します。
アイコンとかを作るときは、最初から思いっきり大きなサイズで作っておこう !!
拡大は、エッジがぼやけてどうしようもなくなるけど、縮小は簡単だから。
場合によるけど、はまったら凄く便利な画像形式
指定した部分だけが自動的に伸縮して周りに合わせてくれる。
変形しても型崩れしない画像Nine Patch ( ナインパッチ ) 画像形式
変形してもそれなりのデザインを保っている
これを
NinePatch フォーマット画像の作り方上下左右の端 1ライン分のところにエディタを使って黒いラインを引く
上と左の端に引いた黒の部分が、自動的に引き伸ばされるところ下と右の端に引いた黒の部分が、コンテンツ領域 (ラベル文字列が乗っかる部分 )
NinePatch フォーマット画像の作り方
あらかじめボタンのようなデザインの画像を png形式で作っておく
android-sdk-windows\tools下にある draw9patch.bat をダブルクリック
エディタが立ち上がるので、先の画像をドラッグ & ドロップ
NinePatch フォーマット画像の作り方上下左右の端 1ライン分のところにエディタを使って黒いラインを引く
上と左の端に引いた黒の部分が、自動的に引き伸ばされるところ下と右の端に引いた黒の部分が、コンテンツ領域 (ラベル文字列が乗っかる部分 )
ベクター形式画像リソース ShapeDrawable
SVG のようなベクター形式画像
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/
apk/res/android"android:shape="rectangle"><solid android:color="#FF666666"/><corners android:radius="3dp" />
</shape>
res/drawable の下に ???.xml の名前で置く
ImageView内の画像データの自動リサイズScaleType について
ImageView の ScaleType プロパティの使い方の例
ImageView image = new ImageView(this);
image.setImageResource(R.drawable.hogehoge);
image.setScaleType( ImageView.ScaleType.CENTER_CROP);
※ 余白領域を含めた範囲内で元の画像の縦横比を維持ながら拡大し中央に寄せる
ImageView の ScaleType についてCENTER リサイズせず画像を中央に寄せる
CENTER_CROP 余白領域を含めた範囲内で元の画像の縦横比を維持ながら拡大し中央に寄せる
CENTER_INSIDE 余白領域を除いた範囲内で元の画像の縦横比を維持ながら拡大し中央に寄せる
FIT_XY 元の画像の縦横比を維持せず枠内ぎりぎりまで拡大
FIT_START 元の画像の縦横比を維持しつつ枠内ぎりぎりまで拡大し左上端に寄せる
FIT_CENTER 元の画像の縦横比を維持しつつ枠内ぎりぎりまで拡大し中央に寄せる
FIT_END 元の画像の縦横比を維持しつつ枠内ぎりぎりまで拡大し右下端に寄せる
MATRIX 描画時に Matrix を使用
Java のプログラムから長さの指定を行うとき指定できる長さの単位は、下記のどちらか
(1) px (ピクセル )(2) dp 、 sp ( 密度非依存ピクセル )
アプリ内では、 (1) または (2) に統一される。
※ AndroidManifest.xml android:anyDensity で指定 (後述 )
px指定の場合どうするのか?fugafuga_box.setTextSize(12sp) … なんてのはム
リ
こう書きます。
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager() .getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
float textSize = density * 12.0f;
fugafuga_box.setTextSize(textSize);
DisplayMetrics について
widthPixels 画面の横幅(ピクセル数)
heightPixels 画面の縦幅(ピクセル数)
xdpi 横方向の実質ピクセル密度( DPI)
ydpi 縦方向の実質ピクセル密度( DPI)
density ( 160dpi のスクリーンでは1、 240dpi スクリーンでは 1.5 …)論理ピクセル密度のスケーリングファクタ
densityDpi (mdpi のとき 160 、 hdpi のとき 240 …)論理ピクセル密度
scaledDensity 標準文字サイズを意識したスケーリングファクタ
AndroidManifest.xml による解像度対応の指定<supports-screens
android:smallScreens="true"android:normalScreens="true"android:largeScreens="true"android:anyDensity="true"/>
~ Screens アプリケーションがそのサイズのスクリーンに対応するかどうかを示すもの
anyDensity Java プログラムが自らピクセル密度を意識して位置や長さを計算しているかどうかを示すもの
true のときピクセル密度を意識している。だから API の引数は「 px 」単位false のときピクセル密度を意識していない。 API の引数は単位は「 dp 」で、 OS側で自動的に処理を行う。
AVD -- いつものやつ (Android Virtual Device) で画面をテストする起動 : Eclipse の Window メニュー⇒ Android SDK and ADV Manger
(1) 画面サイズの指定 -- 「 Skin 」項目で指定Built-in: QVGA (240 x 320)
HVGA (320 x 480) WVGA (480 x 854) … 他
または、Resolution: 横ピクセル数、縦ピクセル数を入力
(2) 画面密度の指定Hardware項目で Property リストに下記の項目を追加
Abstructed LCD densityvalue に 160 とか 240 とかの値を設定する
(3) ついでに、 OS バージョンの指定も
(4) 名前を付けて、 Generate する。
AVD で指定できるハードウェア特性
入力系タッチスクリーン、トラックボール、キーボード、 Dpad
センサー等カメラ、 GPS 、加速度計
オーディオオーディオ録音、オーディオ再生
その他GSM モデム、 SD カード、バッテリ
サイズの指定デバイス RAM サイズ、キャッシュパーティション サイズカメラの水平最大ピクセル、カメラの垂直最大ピクセル
上記全て、 Hardware項目で Property リストに項目を追加して指定
AVD でテスト
画面関連機能エミュレータ画面が大きすぎる場合、 Launch Options の Scale display to real size で指定するScreen Size(in) と Monitor dpi を設定
Ctl + F12 -- 画面を横に
入出力関連F6 トラックボールモードのトグルetc etc
OpenWnn ではどうやっているのか?■お約束の AndroidManifest.xml
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:anyDensity="true"/>
OpenWnn ではどうやっているのか?■drawable について
res /drawable /drawable-hdpi /
キートップデザイン等、オートスケールでごまかせないものは、それぞれ用意
絵文字に関しては drawable のみ
キーの部分は、 9-patch 画像です。
OpenWnn ではどうやっているのか?■画面向きの判定
public void onConfigurationChanged(Configuration config) {
int displayOrientation =
(config.orientation == Configuration.ORIENTATION_LANDSCAPE) ?
DefaultSoftKeyboard.LANDSCAPE : DefaultSoftKeyboard.PORTRAIT;
}
この後、要するに LayoutInflater を使って、縦向き /横向きのキーボードレイアウトをロードしている。
OpenWnn ではどうやっているのか?■ハードウェアキーを使用しているかどうかの判定
public void onConfigurationChanged(Configuration config) {int hiddenState = config.hardKeyboardHidden;...
ハードウェアキー使用中は、ソフトウェアキーボードはうざいので隠します。
if (!mHardKeyboardHidden) { mMainView.removeView(mKeyboardView);}
OpenWnn フリック入力対応版ではどうやったのか?--- バグ減らしのちょっとしたコツ
■ AndroidManifest.xml
API Level は、 Android1.5以上対応ということで、
<uses-sdk android:minSdkVersion="3" />
■Project Build Target
プロジェクトのプロパティ⇒ Android Project Build Target⇒ で
新しいコードを追加したら、 Project Build Target を色々変えて試してみる。
OpenWnn フリックの場合、現在のところ Android 2.3.1
OpenWnn フリック入力対応版の企画~製品開発までの流れ
あらかじめ言っておきますが、うちの製品開発プロセスでは わりと異例 の方です。
■製品企画 1
嫁 : 「旅行に行くの~ Google Map で地図が見れたらとっても便利そう」
俺 : 「じゃ Google携帯にすれば?」
国内初の Android携帯 HT-03A購入決定まるで、テレビ CM のお約束のような流れ
OpenWnn フリック入力対応版の企画~製品開発までの流れ■製品企画 2
しばらく経ってから
嫁 : 「メール打つとき、この日本語の入力が xxxx 」とおっしゃられたわけです。何度も。
俺 : 「 Google携帯にすれば」と言った手前、何とかしなきゃいけない状態だった。立場上。
OpenWnn フリック入力対応版の企画~製品開発までの流れ■製品企画 3
で、まったくもってたまたま、Android のソースコードをダウンロード。そこに OpenWnn のソースがあった。
HT-03A の日本語 IME イコール OpenWnn のことだと思い込んでいた俺は、「改造しちゃえ」と思った。
以上
OpenWnn フリック入力対応版の企画~製品開発までの流れ■製品開発はもっと簡単
その週、お客様との飲み会があって Android を見せびらかした俺
客 : 「ほー これが TV CM でやってるあれですか !! 」
俺 : 「ほらほらー こんなこともでますよ~」
俺 : 「早々に何らかの自社製品を公開するつもりです~ 」
OpenWnn フリック入力対応版の企画~製品開発までの流れ
■製品開発はもっと簡単
で、家に帰って酔った勢いのまま OpenWnn を改造、そのままマーケットに公開。
マーケット公開直前にアプリのアイコンをアップロードしなければいけないことに気づいて、 15 分ほどでデッチあげました。
※ そのまま現在のアイコンとなりました。
OpenWnn フリック入力対応版の企画~製品開発までの流れ■フィードバック&バージョンアップ
公開して 2時間後には、フィードバックのメールをいただきました。「 2chをご覧になってください」
招待をうけて 2ch の掲示板にいくと何やら盛り上がっていて、掲示板が要望リスト状態になっていた。それを見てバージョンアップ ⇒ さらに盛り上がった という経緯
引用させていただきました
梅田 郁 様ソフトウェア技術ドキュメントを勝手に翻訳あんざいゆき 様Y.A.M の 雑記帳有山 圭二 様 解像度の異なる端末に対応するその他、高度な技術情報を惜しみなくご提供いただいた方々に深い感謝の意を表します。
Fin
ご聴取いただき、誠に有難うございます。また、どこかでお会いしましょう。