タブレットUIアンチパターン

はじめに

image

Android Developersではいくつかのページに渡ってタブレット端末のUI設計について説明しています。 本記事ではそれらの説明を元に、タブレットでアプリを表示した際に問題となりやすいデザインアンチパターンについて説明します。

参考URL

シングルペインレイアウト

Android Developersではタブレット向けUIとしてマルチペインレイアウトを推奨しています。 これはタブレットにおけるシングルペインレイアウトが以下のような様々な問題を生みやすいためです。

ListViewの全幅表示

タブレットの横向き画面でシングルペインレイアウトのListViewを全幅表示すると個々の要素の表示領域が大幅に拡大される上に表示可能なリスト要素数が減るため、デザイン上の問題が非常に多くなります。 Android Developersでも「ListViews and menus should not use the full screen width.」と明記されています。

ボタンの全幅表示

シングルペインレイアウトでButtonの幅をmatch_parentとしていた場合、タブレットではボタンの幅が広くなりすぎる場合があります。 このようなボタンは大抵幅のみが拡大されるため、Android Developersでは「10 x 0.5-inch buttons」と表現されています。

TextViewの全幅表示

シングルペインレイアウトでTextViewの幅をmatch_parentとしていた場合、タブレットでは表示文字数が多くなりすぎる場合があります。 Android Developersでは行あたりの文字数は50-75文字程度が最適であり、最大でも100文字程度とされています。 (ただし、これは英語圏の話なので日本語環境では最適な文字数は異なると思われます)

EditTextの全幅表示

シングルペインレイアウトでEditTextの幅をmatch_parentとしていた場合、タブレットでは表示文字数が多くなりすぎる場合があります。 特に一行のEditTextの場合、入力文字数制限よりもはるかに幅が大きくなってしまう場合があります。

シングルペインのまま解決する

マルチペインレイアウトにすることが推奨されていても、やはり導入が難しい場合もあります。 そのような場合のための解決方法をいくつか紹介します。

コンテンツの幅を制限し、画面全体を中央寄せしてしまうことで、シングルペインレイアウトの横幅に関する問題を緩和することができます。 02.png

画面内の要素を並び替え、マルチペインレイアウト風にみせる方法も有効です。 この方法では画面の表示単位をスマートフォンと分ける必要がないため、Master/Detailパターンのマルチペインレイアウトを導入するよりも簡単です。 03.png

リストコンテンツの場合、複数列ならべる(グリッド化する)ことで横方向への融通が効くようになります。 RecyclerViewを利用すると様々な表示に対応できます。 04.png

参考URL:

http://developer.android.com/distribute/essentials/quality/tablets.html#optimize-layouts http://developer.android.com/training/design-navigation/multiple-sizes.html#multi-pane-layouts

画面方向が固定されている

スマートフォンでは縦方向固定、タブレットでは横方向固定という仕様のアプリも見かけますが、できるだけ両方向に対応すべきです。 特にListViewを使った画面では縦方向で使えたほうが情報量が多くなって便利になります。 ただし、画面回転に関する注意点として、Android Developersでは画面は向きが変わっていても同一の機能を持つように努力すべきと書かれています。 つまり、マルチペインレイアウトの画面は回転させてもマルチペインレイアウトと同等の機能を提供するよう努力すべきということで、なかなか難しい問題です。 Android Developersではマルチペインレイアウトを回転させた場合のレイアウトパターンについてはいくつか提案されています。

参考URL:

http://developer.android.com/design/patterns/multi-pane-layouts.html http://developer.android.com/training/design-navigation/multiple-sizes.html#orientations

また、SlidingPaneLayoutを使うと回転にも対処しやすくなります。

ダイアログの多用

タブレットに限らずAndroidアプリ全般でダイアログの多用は非推奨となっていますが、特にマルチペインレイアウトとダイアログの組み合わせは画面のどの領域がダイアログの発生要因なのかわかりづらくなる場合があります。 ダイアログを利用すべきパターンについてはAndroid Developersに明確な指針があるため、これに従いましょう。

参考URL:

http://developer.android.com/design/patterns/confirming-acknowledging.html

特に、以下のようなダイアログはマルチペインレイアウトと相性が悪くなります。

読み込み中ダイアログ

Master/DetailパターンにおいてDetail領域の表示に読み込み中ダイアログを表示した場合、ダイアログが表示されている間はMaster領域も操作できなくなってしまいます。 このような場合はダイアログを利用せず、Detail領域内でProgressBarを表示したほうが良いでしょう。

入力エラー時のダイアログ

EditTextなどの入力チェックでダイアログを利用している場合も画面全体が操作不能になってしまい不便です。 入力部品にはsetErrorメソッドが用意されているので、これで代用可能かどうか検討しましょう。

ActionBarタブ・ドロップダウンリストの置き換え方法まとめ

はじめに

API level 21以降、NAVIGATION_MODE_LISTやNAVIGATION_MODE_TABSといったActionBarと連動したナビゲーション要素が非推奨となりました。 これらのUIの置き換え方法についてはAndroid Developersで該当定数のリファレンスに「Consider using other common navigation patterns instead.」と記述されており、リンク先のページの「Changing view within a screen」という項目では以下のような実装案が文字列でのみ提示されています。

Examples of such view changes are:

  • Switching views using tabs and/or left-and-right swipes
  • Switching views using a dropdown (aka collapsed tabs)
  • Filtering a list
  • Sorting a list
  • Changing display characteristics (such as zooming)

具体的な置き換え例がないためか、いまでもそのまま利用しているアプリも多いですが、非推奨となってしまったからにはいつかは置き換える必要があります。 特にNAVIGATION_MODE_TABSはAPI level 21以降導入されたToolbarと共存できないため、できるだけ早く他の実装に置き換えるべきです。

ActionBar.NAVIGATION_MODE_TABS

ActionBar.NAVIGATION_MODE_TABSは名前の通りActionBarと一体化したタブUIを提供していましたが、API level 21以降非推奨となりました。 同様の機能を提供していたappcompat-v7版もr21以降非推奨となっています。

このタブUIはスマートフォンではActionBarの真下に表示される全幅のタブバーとして表示されますが、横画面(landscape)やタブレットではではActionBar内に格納され、さらに表示領域が足りない場合はドロップダウンリストになります。 さらにActionBarの一部だったためにNavigationDrawerよりも上のレイヤーに表示されてしまうなど、独特の扱いづらさがありました。

ActionBar.NAVIGATION_MODE_TABSの大半はViewPagerと組み合わせて利用されていたので、本項でもViewPagerとの組み合わせについて説明します。 また、Material DesignガイドラインにもタブUIの説明があるので、こちらも参照してください。

Tabs - Components - Google design guidelines

PagerTitleStrip/PagerTabStrip で置き換える

PagerTitleStripおよびPagerTabStripはViewPagerと合わせて実装されたViewPagerの上下にページ名を表示できるUIです。 ただし、これは見た目からもわかる通り現在表示中のページ名を表示するインジケータとしての役割が強く、ActionBarタブの置き換えにはあまり向いていません。 また、ViewPagerと密着したレイアウト構造のため、ActionBarと連動してアニメーションで非表示にするといったUIにしづらいこともデメリットになります。

PagerTitleStrip、PagerTabStripはViewPagerの見た目と違いは下記のブログ記事が詳しいです。

PagerTitleStripよりPagerTabStripのほうがいいと思う | made in kuluna

SlidingTabs で置き換える

SlidingTabsはAndroid Developersのサンプル(Apache License 2.0)に含まれているタブ実装になります。 「Sliding」という名の通り、ページ遷移時に現在ページを示すインジケータがスライドするアニメーションが入ることが特徴です。 SlidingTabsに関するサンプルは2種類用意されていますが、サンプルアプリの実装の違いなのであまり意識しなくても良いでしょう。

SlidingTabsBasic | Android Developers SlidingTabsColors | Android Developers

このサンプルアプリはレイアウトが標準的でない上あまり説明が親切でないため、実際に導入する際の手順を簡単に説明します。 前提条件として、appcompat-v7のToolbarをある程度実装してるプロジェクトを想定しています。

まず、サンプルアプリのviewクラス2つを自分のプロジェクトにコピーします。

SlidingTabLayout.java SlidingTabStrip.java

次に、レイアウトファイルでToolbarの真下にSlidingTabLayoutを配置します。 このとき、SlidingTabLayoutのbackgroundをcolorPrimaryにしておくとToolbarと並んだときに背景色が同色になります。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize">
    </android.support.v7.widget.Toolbar>

    <MY_PACKAGE.SlidingTabLayout
        android:background="?attr/colorPrimary"
        android:id="@+id/sliding_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1" />
</LinearLayout>

ソース側ではSlidingTabLayout#setViewPagerにより対象のViewPagerを設定するだけでViewPagerの動きと連動するようになります。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity);

    Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
    setSupportActionBar(toolbar);

    ViewPager viewpager = (ViewPager) findViewById(R.id.view_pager);
    viewpager.setAdapter(new MyAdapter());

    SlidingTabLayout slidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
    slidingTabLayout.setViewPager(viewpager);
}

これだけでも動作するようになっていますが、SlidingTabLayoutはToolbarとの連携を意識したクラスになっていないため、選択中タブのフッターバーデフォルト色が固定値になっています。 SlidingTabLayout#setSelectedIndicatorColorsで色を指定することでも設定できますが、Toolbarと背景色をあわせるのであれば、フッターバーはアクセント色(colorAccent)を読み込むようにしたほうが良さそうです。

SlidingTabString.java 75行目の以下の文を置き換えます。

mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);

このとき、appcompat-v7を利用している場合はR.attr.colorAccentではなくandroid.support.v7.appcompat.R.attr.colorAccentを指定しないとうまく取得することができません。

TypedValue accentValue = new TypedValue();
context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr.colorAccent, accentValue, true);
final int accentColor= accentValue.data;
mDefaultTabColorizer.setIndicatorColors(accentColor);

以上で最低限の設定は完了です。 SlidingTabLayout/SlidingTabStripはあまり複雑な処理はしていないので、このようにデザインやアニメーションなどをカスタマイズしましょう。

PagerSlidingTabStrip で置き換える

jpardogo/PagerSlidingTabStrip

PagerSlidingTabStripというMaterialDesignに対応したタブUIライブラリが提供されているようです。 カスタマイズに利用できるattr属性も多いようなので、SlidingTabsをカスタマイズするよりも簡単に好みのデザインにできそうです。

NAVIGATION_MODE_LIST

ActionBar.NAVIGATION_MODE_LISTはActionBarから呼び出せるドロップダウンリストのUIを提供していましたが、API level 21以降非推奨となりました。 同様の機能を提供していたappcompat-v7版もr21以降非推奨となっています。 NAVIGATION_MODE_TABSと異なり、現状はNAVIGATION_MODE_LISTはToolbarを利用した場合でも動作しますが、やはり早い段階で置き換えたほうが良いでしょう。

Material DesignsガイドラインのMenusコンポーネントのページに近いUIの説明があります。 Menus - Components - Google design guidelines

Spinner(with Toolbar) で置き換える

NAVIGATION_MODE_LISTはもともとSpinnerAdapterを利用するようになっており、UIもSpinnerとほぼ一緒です。 そのため、Toolbar内にSpinnerを配置し、元と同じAdapterをセットしてやるだけでほぼ同じ見た目のまま置き換えることができます。

元のNAVIGATION_MODE_LISTによる実装が以下のようになっていたとします。

@Override
protected void onCreate(Bundle savedInstanceState) {

    // 略

    getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    getSupportActionBar().setListNavigationCallbacks(
            ArrayAdapter.createFromResource(this, R.array.list_items, android.R.layout.simple_spinner_dropdown_item),
            new ActionBar.OnNavigationListener() {
                @Override
                public boolean onNavigationItemSelected(int i, long l) {
                    // 処理
                    return true;
                }
            });
    getSupportActionBar().setDisplayShowTitleEnabled(false);
}

Spinnerに置き換えるため、Toolbarの中にSpinnerを配置します。 (下記レイアウトはToolbarと関係ない部分を省略しています)

    <android.support.v7.widget.Toolbar
        android:id="@+id/tool_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize">

        <Spinner
            android:id="@+id/tool_bar_spinner"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </android.support.v7.widget.Toolbar>

次に、先述のActivityの実装を以下のように変更します。

@Override
protected void onCreate(Bundle savedInstanceState) {

    // 略

    Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
    setSupportActionBar(toolbar);

    Spinner spinner = (Spinner) toolbar.findViewById(R.id.tool_bar_spinner);
    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            // 処理
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });
    spinner.setAdapter(ArrayAdapter.createFromResource(this, R.array.list_names, android.R.layout.simple_spinner_dropdown_item));
}

これでほぼ同じ見た目のままToolbar内のSpinnerに実装を置き換えることができました。

2014発売Android端末のdp解像度まとめ

はじめに

Android端末は機種数が多く、OSバージョンやハードウェアがそれぞれ異なるためにAndroidでアプリを作ることは大変だと言われています。 特にディスプレイについてはそれぞれが異なった画面サイズや解像度を持つため、Androidの画面設計は複雑だと思われがちです。

実際、OpenSignalのAndroid断片化調査の中でも以下のような画像とともに画面サイズの断片化について触れています。

image

しかし、Androidにはdp(密度非依存ピクセル)という実際の画面サイズ、解像度に依存しない形で画面を扱うための仕組みが用意されており、このdpを使うことでAndroidの画面サイズ断片化への対応コストは大幅に削減することができます。 dpの概要については過去に記事を書きましたので、そちらを参照してください。

いまさら聞けないdp入門

断片化とdpについての基本的な説明は下記ブログに簡単な例と図入りでまとめられているので、ぜひ一読しておきましょう。

The Android Screen Fragmentation Myth | Rusty Rants

本題

最近のAndroid端末の画面サイズ断片化状況を把握するため、2014年に国内キャリアから発売された端末のdp解像度を調査しました。 デバイスの分類については、Android Developers上ではフォン(スマートフォン)とタブレットの2種類となっていますが、どちらにも含まれない端末があるため、 記事中ではそれらの端末を「ファブレット」として分類しました。

image

この記事の調査で作成した一覧表(Googleスプレッドシート)

http://goo.gl/spJxXq

スマートフォン

Android Developersの定義では、スマートフォン端末は320-384dpの横幅を持つとされています。 一部の端末は物理ボタンを持っており、ナビゲーションバーが表示されないためアプリを描画可能な範囲が広くなりますが、Kitkat以降ではナビゲーションバーの制御も可能になっているため今回の調査では物理ボタンの有無を区別していません。

スマートフォンのdp解像度

dp解像度 量子化密度 端末数
360x640 hdpi 1
360x640 xhdpi 8
360x640 xxhdpi 22
360x640 xxxhdpi 5
320x569.3 hdpi 1

dp解像度の分類でみると、ほぼすべての端末が360x640dpとなっており、最近発売されたスマートフォンに対してはこのdp解像度を基準にデザイン設計を行えば良いことがわかります。 ただし横幅320dpの機種も1機種のみ発売されているため、320dpでも崩れないことを確認したほうが良いでしょう。

スマートフォンの一覧

スマートフォン端末の解像度とdpはそれぞれ以下のようになっています。 GALAXY Note Edgeのエッジスクリーン領域は除外しています。

機種名 対角線長 W(px) H(px) dpi 量子化密度 W(dp) H(dp) 備考
AQUOS PHONE SERIE mini SHL24 4.5 1080 1920 480 xxhdpi 360 640
URBANO L02 4.7 720 1280 320 xhdpi 360 540 物理ボタン
G Flex LGL23 6 720 1280 320 xhdpi 360 540
HTC J butterfly HTL23 5 1080 1920 480 xxhdpi 360 640
TORQUE G01 4.5 720 1280 320 xhdpi 360 640 物理ボタン
URBANO L03 5 1080 1920 480 xxhdpi 360 640 物理ボタン
AQUOS SERIE SHL25 5.2 1080 1920 480 xxhdpi 360 640
GALAXY S5 SCL23 5.1 1080 1920 480 xxhdpi 360 640 物理ボタン
Xperia ZL2 SOL25 5 1080 1920 480 xxhdpi 360 640
isai FL LGL24 5.5 1440 2560 640 xxxhdpi 360 640
isai VL LGV31 5.5 1440 2560 640 xxxhdpi 360 640
URBANO V01 5 1080 1920 480 xxhdpi 360 640 物理ボタン
Xperia Z3 SOL26 5.2 1080 1920 480 xxhdpi 360 640
GALAXY Note Edge SCL24 5.6 1440 2560 640 xxxhdpi 360 640 物理ボタン・エッジスクリーン
GALAXY S5 SC-04F 5.1 1080 1920 480 xxhdpi 360 640 物理ボタン
AQUOS ZETA SH-04F 5.4 1080 1920 480 xxhdpi 360 640
Disney Mobile on docomo SH-05F 5 1080 1920 480 xxhdpi 360 640
Xperia Z2 SO-03F 5.2 1080 1920 480 xxhdpi 360 640
Xperia A2 SO-04F 4.3 720 1280 320 xhdpi 360 640
ARROWS NX F-05F 5 1080 1920 480 xxhdpi 360 640
らくらくスマートフォン3 F-06F 4.5 720 1280 320 xhdpi 360 640
GALAXY Note Edge SC-01G 5.6 1440 2560 640 xxxhdpi 360 640 物理ボタン・エッジスクリーン
GALAXY S5 ACTIVE SC-02G 5.1 1080 1920 480 xxhdpi 360 640 物理ボタン
AQUOS ZETA SH-01G 5.5 1080 1920 480 xxhdpi 360 640
Disney Mobile on docomo SH-02G 5.5 1080 1920 480 xxhdpi 360 640
Xperia Z3 SO-01G 5.2 1080 1920 480 xxhdpi 360 640
Xperia Z3 Compact SO-02G 4.6 720 1280 320 xhdpi 360 640
ARROWS NX F-02G 5.2 1440 2560 640 xxxhdpi 360 640
AQUOS PHONE Xx mini 303SH 4.5 1080 1920 480 xxhdpi 360 640
AQUOS CRYSTAL 305SH 5 720 1280 320 xhdpi 360 640
AQUOS Xx 304SH 5.2 1080 1920 480 xxhdpi 360 640
シンプルスマホ2 401SH 4.5 720 1280 320 xhdpi 360 640
Xperia Z3 401SO 5.2 1080 1920 480 xxhdpi 360 640
CRYSTAL X 402SH 5.5 1080 1920 480 xxhdpi 360 640
AQUOS PHONE ef WX05SH 4 480 854 240 hdpi 320 569.3
DIGNO T 302KC 4.5 540 960 240 hdpi 360 640 物理ボタン
DM016SH 5.2 1080 1920 480 xxhdpi 360 640

ファブレット

ファブレットの定義はAndroid Developers上にはありません。 ただし、分類表で未分類の短辺が384dpより大きく、600dpよりも小さい端末はファブレットと呼べそうです。 この記事ではAndroid Developersに従い短辺が600dpのものはタブレット扱いとしましたが、これらの端末は7インチ前後のものが大半のようなので、今後ファブレットとして扱われるようになる可能性もあります。

ファブレットのdp解像度

今回の分類ではファブレット端末は2機種しか該当しません。

機種名 対角線長 W(px) H(px) dpi 量子化密度 W(dp) H(dp)
Xperia Z Ultra SOL24 6.4 1080 1920 320 xhdpi 540 960
Nexus 6 5.96 1440 2560 560 560dpi 410 730

Xperia Z Ultraの540x960がタブレット最小dp解像度の短辺を60dp短くしただけなのに対して、Nexus6の410x730dpはかなり特殊です。 Nexus6が他のWQHD端末と同様のxxxhdpiであれば360x640dpの標準的なスマートフォンだったはずですが、わざわざ560dpiを定義して410x730dpとすることでこの数字を中心としたファブレットという枠組みを作ろうとしているのかもしれません。 今後のガイドラインの更新に期待しましょう。

タブレット

Android Developers上の分類ではタブレットは短辺600-800dp、長辺800-1280dpの端末を指します。 スマートフォンと違い、量子化密度が高い端末はあまり多くありません。 タブレットのみ、表中のW=長辺、H=短辺としています。

タブレットのdp解像度

dp解像度 量子化密度 端末数
960x600 xhdpi 3
1024x768 xhdpi 1
1280x800 mdpi 1
1280x800 hdpi 2
1280x800 xhdpi 3

傾向としては、タブレット端末は最小の短辺600dpと最大の1280dpに集中しています。 それぞれ7インチと10インチの端末が多く、8インチでは混在しています。 この2つはアスペクト比も同じため、デザイン上それほど大きな問題にはならないでしょう。 問題はNexus9の1024x768で、アスペクト比が4:3のスクエアディスプレイ端末になります。 とはいえ、960x600dpに対応できていれば縦方向の拡大幅が大きいだけなので、縦スクロールの多いAndroidアプリでは極端な表示崩れとはならないはずです。

タブレットの一覧

機種名 対角線長 W(px) H(px) dpi 量子化密度 W(dp) H(dp) 備考
AQUOS PAD SHT22 7 1920 1200 320 xhdpi 960 600
Xperia Z2 Tablet SOT21 10.1 1920 1200 240 hdpi 1280 800
GALAXY Tab S SCT21 10.5 2560 1600 320 xhdpi 1280 800 物理ボタン
ASUS MeMO Pad 8 AST21 8 1920 1200 320 xhdpi 960 600
Xperia Z2 Tablet SO-05F 10.1 1920 1200 240 hdpi 1280 800
GALAXY Tab S 8.4 SC-03G 8.4 2560 1600 320 xhdpi 1280 800 物理ボタン
ARROWS Tab F-03G 10.5 2560 1600 320 xhdpi 1280 800
AQUOS PAD SH-06F 7 1920 1200 320 xhdpi 960 600
Nexus9 8.9 2048 1536 320 xhdpi 1024 768
MediaPad M1 8.0 403HW 8 1280 800 160 mdpi 1280 800

まとめ

スマートフォンタブレットのどちらにも分類できない端末が出てきたことで、全体としては画面サイズの断片化が進んだ形になっています。 ただしスマートフォンタブレットに該当する端末に関してはdp解像度が集中していること、サポート範囲が明確に示されていることから、カテゴリの中での断片化はほぼ免れているといっても良いでしょう。 ファブレットに関してはまだ機種が少ないこともありどのような形に落ち着くのか不明ですが、ひとまずNexus6の410dpまでサポートできるようにスマートフォン向けレイアウトを組んだほうが良いかもしれません。 横幅540dpのXperia Z Ultraの存在はAndroid Developersでタブレットの分類を「sw600dp」としているため対応が難しくなっています。タブレット判定用のsw600dpを変更することは難しいので、何かルールが決まるまでは対応端末としないか、多少使いづらくともスマートフォン向けレイアウトで対応するしかなさそうです。

AppIndexingについて

AppIndexingとは

AppIndexingとは、ウェブページURLやキーワードとアプリの特定画面へのディープリンクを紐付け、Google検索結果から直接アプリの特定画面を起動させるための仕組みです。 現在はウェブサイトにアプリ用ディープリンクを埋め込む方法(狭義のAppIndexing)と、アプリ側で特定のキーワードとアプリ用ディープリンクを埋め込む方法(AppIndexingApi)の二種類が提供されています。

https://developers.google.com/app-indexing/?hl=ja

実際の動作については以下の記事がわかりやすくまとめられています。

App Indexing のススメ - pixiv engineering blog

ディープリンクについて

ディープリンクとは、アプリのあるコンテンツについて直接アクセスするためのリンクのことです。 AndroidアプリにおいてはAndroidManifest.xml内に<data>を指定する形で記述された<intent-filter>の実装と、その<data>で定義されたURIを指します。 http://example.com/gizmos?1234 のようなhttpスキームやexample://gizmos?1234のような独自のスキームを定義したものが利用できます。

アプリへのディープリンク追加

AppIndexing、AppIndexingApiともにアプリにディープリンクを追加しておく必要があります。 Androidアプリにディープリンクを指定する方法は次の通りです。

  1. AndroidManifest.xmlで対象Activityに<intent-filter>要素を追加します。
  2. ACTION_VIEWを指定する<action><intent-filter>に追加します。
  3. 受け付けるディープリンクの仕様に従って<data><intent-filter>に追加します。
  4. BROWSABLEを指定する<category><intent-filter>に追加します。
  5. DEFAULTを指定する<category><intent-filter>に追加します。(任意)

上記のうち、DEFAULTカテゴリの指定のみ任意となります。 DEFAULTカテゴリを指定しなかった場合、Google検索結果からアプリへのディープリンクを起動することはできますが、Google検索結果以外のページから対象ウェブページへリンクした際にアプリへのディープリンクを起動することができなくなります。

https://developers.google.com/app-indexing/webmasters/app?hl=ja

例として、http://example.com/gizmosで始まるディープリンクで起動するアクティビティを設定する場合、以下のように記述します。

<activity android:name="com.example.android.GizmosActivity"
           android:label="@string/title_gizmos" >
     <intent-filter android:label="@string/filter_title_viewgizmos">
         <action android:name="android.intent.action.VIEW" />
         <!-- Accepts URIs that begin with "http://example.com/gizmos” -->
         <data android:scheme="http"
               android:host="example.com"
               android:pathPrefix="/gizmos" />
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
     </intent-filter>
 </activity>

注意点

アプリへディープリンクを追加する際、いくつかの注意点があります。

First Click Freeに従う

First Click Freeとは、2008年に制定されたGoogleのウェブインデックスポリシーのことです。 名前の通り、Google検索から最初のクリックで遷移したページは登録・購読不要で閲覧可能とすることで会員制ページもウェブインデックスに含まれるようになっています。 http://web-tan.forum.impressrd.jp/e/2008/10/28/4293

ディープリンクによってアプリが起動される場合、このFirst Click Freeに従う必要があります。 すなわち、ディープリンクによってアプリが起動される場合、ウェブページと同じコンテンツを直接ユーザーに表示しなければいけません。 以下のような挙動はFirst Click Freeに違反しています。

  • コンテンツの表示を遮るプロンプトを表示する
  • スプラッシュ画面を表示する
  • ログイン画面を表示する
  • インタースティシャルページ(ページ遷移の際に経由させる画面)を表示する

http://googlewebmastercentral.blogspot.jp/2008/10/first-click-free-for-web-search.html

戻る動作

ディープリンクによってアプリが起動された画面から「戻る」が押された場合、遷移元(通常は検索結果)のページに戻る必要があります。 また、戻る際にアプリ内の他のコンテンツや確認のプロンプトが表示されることのないようにします。

AppIndexing

AppIndexingはサーバ側の設定によりウェブサイトとディープリンクの紐付けを行う方法です。 本来AppIndexingはAppIndexingApiも含んだアプリのディープリンク提供サービスを指しますが、以前はこの方法しか提供されていなかったため、単にこの方法のみを指してAppIndexingと呼ぶ場合もあります。

https://developers.google.com/app-indexing/webmasters/server?hl=ja

Playコンソールのウェブサイトを確認する

Playコンソール上のウェブサイトが確認済みである必要があります。 (ウェブサイトが複数存在する場合、すべて確認済みである必要があります)

https://support.google.com/googleplay/android-developer/answer/6041489

ウェブサイトへのディープリンク追加

ウェブサイトへのディープリンク追加方法は2種類提供されています。 いずれの場合でもディープリンクを指定するためのアプリURIは以下のフォーマットに従う必要があります。

android-app://{package_id}/{scheme}/{host_path}

パッケージIDがcom.example.androidの場合、以下のような設定が可能です。

ディープリンク アプリURI
http://example.com/gizmos?1234 android-app://com.example.android/http/example.com/gizmos?1234
http://example.com/gizmos/1234 android-app://com.example.android/http/example.com/gizmos/1234
http://example.com/gizmos/toys/1234 android-app://com.example.android/http/example.com/gizmos/toys/1234
example://gizmos?1234 android-app://com.example.android/example/gizmos?1234
example://gizmos/1234 android-app://com.example.android/example/gizmos/1234
example://gizmos/toys/1234 android-app://com.example.android/example/gizmos/toys/1234

アプリURIをテストするためにディープリンクテストツールが提供されています。

このツールを使用するとアプリURI

https://developers.google.com/app-indexing/webmasters/test?hl=ja

各ページに実装

ディープリンクの追加を行うページの<head>セクションに<link>要素を追加することで、ウェブページとアプリへのディープリンクを紐付けることができます。

<html>
<head>
  ...
  <link rel="alternate" href="android-app://com.example.android/http/example.com/gizmos" />
  ...
</head>
<body></body>

サイトマップに実装

ウェブサイトのXMLサイトマップ<link>要素を追加することで、ウェブページとアプリへのディープリンクを紐付けることができます。

<?xml version="1.0" encoding="UTF-8" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
 xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
  <loc>http://example.com/gizmos</loc>
  <xhtml:link rel="alternate" href="android-app://com.example.android/example/gizmos" />
</url>
...
</urlset>

AppIndexingApi

AppIndexingApiを利用するとアプリが実装しているディープリンクを直接Googleに通知することができます。 これにより、Google検索アプリ(バージョン3.6以降)のキーワードコンプリートで特定キーワードからアプリへのディープリンクを表示できる他、ウェブページURLを指定することでGoogle 検索結果に表示されるようになります。

AppIndexingApiとAppIndexingの大きな違いは、ウェブページURLとの紐付けではなくタイトル(キーワード)との紐付け機能であることです。 ウェブサイトの都合で一意のURLを生成できないような場合やウェブサイトのないサービスにも導入することができます。 また、検索キーワードを入力する際のキーワードコンプリートとして表示されるため、ブラウザを経由することなく直接アプリが起動されるようになります。

https://developers.google.com/app-indexing/webmasters/appindexingapi?hl=ja

まとめ

よくある疑問まとめ AppIndexingページのFAQも参照してください。

https://developers.google.com/app-indexing/faq?hl=ja

AppIndexingとAppIndexingApiのどちらを実装すれば良いか

ウェブサイトと紐付けを行う場合、AppIndexingApiは対象画面に遷移するまでGoogleにリクエストが送られないため、ウェブインデックスで紐付け処理が行われるAppIndexingのほうが対応が早くなります。 AppIndexingを利用する場合でもAppIndexingとAppIndexingApiはお互いに検索結果、検索アプリで補いあうため、できれば両方実装するのが良いでしょう。

戻る動作の実装が難しい

スプラッシュやlaunchModeなどの不要な設定を排して単純にActivityが起動するようにすれば自然に戻るはずです。

正しく設定しているはずなのに動作しない

チェックリストを参照してください。 ウェブページからディープリンクを起動する場合、検索結果にインデックスされるまで時間がかかる場合があります。

https://developers.google.com/app-indexing/webmasters/checklist?hl=ja

勝手にAppIndexingみたいな挙動になってる

アプリのディープリンクスキームがhttpの場合で、ウェブサイトがPlayコンソールで確認済み、かつウェブサービスのコンテンツページURLとアプリのディープリンクURIが完全に同一の場合、Googleのウェブインデックスで紐付けが行われ、AppIndexingと同じ挙動になります。 …というよりも、この挙動をカスタムスキームで行えるようにしたのがAppIndexing/AppIndexingApiです。 ただし現在はhttpスキームを利用する場合でも明示的にディープリンクの紐付けを行うことが推奨されています。

https://developers.google.com/app-indexing/webmasters/connect?hl=ja

Android 5.0 差分メモ

自分用あとで読むメモ

Android 5.0 概要

Android Lollipop | Android Developers

API 概要

Android 5.0 APIs | Android Developers

API 差分

API Differences between 20 and 21

Support Library 変更点

Support Library | Android Developers

Support Libraryのリビジョンごとの差分は提供されていないようなので、5.0 API差分を元に類推する。

変更点まとめ

重要そうな変更点と関連URL

ActionBar.Tabが非推奨になった

ActionBarのタブが非推奨になった。 今後はcommon navigation patternsに従うようにとなっているが、具体的な実装が見つからない。 非推奨になっていないPagerTabStripを使うか、SlidingTabsを使うと良いかもしれない。

ActionBar.Tab | Android Developers

JobScheduler

端末の状態に応じてバックグラウンドタスクを実行させるJobSchedulerが追加された。 バックポートされてない(今後もされなさそう)ので、使い所が難しそう。

Android 5.0 APIs | Android Developers JobScheduler | Android Developers

Activityの永続化サポート

PersistableBundleというクラスを利用した新しいライフサイクルメソッドが提供された。 これにより、Activityの情報を端末のリブートを超えて保持することができるようになった(と思う)。 同様の機能はSupport LibraryのActionBarActivityにも提供されている。

ActivityのpersistableModepersistAcrossRebootsであればリブート後も設定値を保持するようなのだが、 なぜかattrのページにはalwaysとかtaskOnlyとか書いてあってよくわからない。

R.attr | Android Developers

Activity | Android Developers

Toolbar

ActionBarの新しい実装としてToolbarが追加された。 ActionBarと違い、レイアウトの中に記述できるようになっている。 layout.xmlで定義したものをActionBarActivity#setSupportActionBarに渡して使うらしい。

Toolbar | Android Developers

Material Design

Material Designのサポートはv7-appcompatに追加された。

Support Library Features | Android Developers

Activity遷移アニメーション

新しいActivity遷移アニメーションがActivityOptionsCompatに追加された。 実はActivityOptionsCompatは以前からあったけどあまり使われてなかったようだ。 今回追加されたのはmakeSceneTransitionAnimationだけど他のTransitionも使いたい。

ActivityOptionsCompat | Android Developers

SwitchCompat

Switchのバックポートがv7-appcompatに追加された。

SwitchCompat | Android Developers

DocumentFile

DocumentFileがv4-supportに追加された。 DocumentProviderFileを同じように扱うための仕組みらしい。 ただしオーバヘッドが大きいのでパフォーマンス求めるならDocumentsContractを使えとのこと。 DocumentProviderがバックポートされていないので、おそらくLevel 19以降はDocumentProvider経由、 それ以前ではDocumentFile#fromFile(File)で初期化して以降は同じように扱えるよ、ということかな。

DocumentFile | Android Developers

v7-cardview

CardViewのサポートライブラリが追加された。

Support Library Features | Android Developers

v7-cardview

RecyclerViewのサポートライブラリが追加された。

Support Library Features | Android Developers

v7-palette

画像に合う色を生成できるPaletteのサポートライブラリが追加された。

Support Library Features | Android Developers

v17-leanback

Android TV向けアプリ用のサポートライブラリが追加された。

Support Library Features | Android Developers

【Android】いまさら聞けないdp入門 という記事を更新しました。

Qiitaに書いていた【Android】いまさら聞けないdp入門 - Qiitaという記事を更新しました。 (この記事も元々は同じ内容を記載していましたが、両方メンテすると大変なのでQiitaへのリンクページにしました)

さすがに公開から1年以上経つとAndroid Developersのリンク切れ(というか関係ないページへのリダイレクト)や古くなってしまった記述が多く、「dpとは」以外の部分はだいたい書き直しました。

また、Android Developersの日本語化されたページで用語に訳がついたものはそちらにあわせています。

差分: 「【Android】いまさら聞けないdp入門」の編集履歴 - Qiita

Androidアプリのタブレット対応レイアウトまとめ

はじめに

タブレットスマートフォンの最大の違いは画面の横幅です。 Androidアプリをタブレット対応させる際は、いかにして画面の横幅を埋めるかが重要になります。 この記事では余白を埋める様々なパターンについて解説しています。

Android Developersの以下のページを参考にしてください。 Planning for Multiple Touchscreen Sizes | Android Developers Supporting Tablets and Handsets | Android Developers Multi-pane Layouts | Android Developers

各画面内での対応

画面遷移やActivity構成に影響を与えずにレイアウトを調整する方法です。 タブレットで見やすくはなりますが、使い勝手の向上に関しては限界があります。

コンテンツを拡大する

画面幅いっぱいにコンテンツを表示できるようにレイアウトを調整する方法です。 コンテンツの拡大はLinearLayoutandroid:layout_weightなどで行います。 横方向にコンテンツを並べるレイアウトと相性がよく、とくにGridViewなどコンテンツをタイル状に並べるレイアウト見栄えがよくなります。

Googleカレンダーの月表示はコンテンツ領域を画面全幅に拡大しています。 01.png

コンテンツの最大幅を決める

Webページなどでよく見かける、コンテンツを中央寄せにして左右に余白をもたせる方法です。 画面幅によってandroid:layout_widthで使用するdimenを切り替えることで実装できます。 特にログイン画面やチュートリアル、入力欄が多い画面は崩れにくくなるので向いていますが、画像や動画などが多く含まれるコンテンツでは情報量が増えないためあまり向きません。 また、背景が白や黒だと手抜きに見えやすいので、ある程度工夫が必要です。

Google Keepでは一覧画面を最大幅で表示し、詳細/編集画面をダイアログのように表示しています。 02.png

コンテンツの配置を変える

縦一列にならんでいたコンテンツを複数列に配置する方法です。 詳細画面などで適用すると画面領域に無駄がなくなり効率的です。 スクロール領域の分割や一部コンテンツの拡大など、使い勝手を向上できる可能性があります。 反面、画像や動画といった大きめのコンテンツがないとごちゃごちゃして読みづらい印象になりがちです。

Youtubeアプリの動画再生画面はコンテンツの再配置を行っています。 03.png

グリッド化

リストコンテンツを複数列に配置する方法です。 コンテンツの配置を変える方法に近いのですが、レイアウト差が少ないコンテンツの繰り返しがある場合に適用します。 ListViewなどAdapterViewを継承したクラスで実装している場合、比較的少ない工数で切り替えできる可能性があります。 OnItemClickListener()setAdapter()など、主要な機能はAdapterViewに定義されているので、コーディング時に気をつければ切り替えは容易になります。 最近ではGoogle Keepのようにコンテンツの高さが異なる場合に余白を詰めて互い違い風にしたグリッドもよく見かけるようになりました。

Google+ではストリームのカードを複数列に配置しています。 04.png

複数画面にまたがる対応

いわゆるマルチペイン化のような方法です。 ここで紹介するのはシングルペイン構造の画面をマルチペイン化する方法ですが、Android Developersではすでにマルチペイン化されたコンテンツのタブレット対応について説明しているページがあります。

ぜひ参考にしてください。

Multi-pane Layouts | Android Developers Planning for Multiple Touchscreen Sizes | Android Developers

メニューの展開

NavigationDrawerなどの普段は隠れているメニューを常時表示させる方法です。 NavigationDrawerActionBarと深く結合しているため、常時表示する際はActionBarDrawerToggleMenuItemなどの処理まで手を加えなくてはいけません。 また、NavigationDrawerを常時表示させた場合、後述するMaster/Detailパターンと重複しやすいことも注意が必要です。

GmailNavigationDrawerに相当する部分がトップ画面で表示されるようになっています。 05.png

Master/Detailパターン

一覧→詳細と画面遷移していたものを一画面に並べ、一覧選択時に詳細部分のみ更新されるようにする方法です。 一般的にマルチペイン化という場合、ほとんどがMaster/Detailパターンを指します。 様々なアプリで利用されていることからわかるとおり見栄え、利便性ともにかなり向上しますが、 一覧/詳細画面の実装によって実装の難易度がかなり違ってくるので個々の画面を作る際にも注意が必要となります。 AndroidにはMaster/DetailsパターンのためにSlidingPaneLayoutが容易されており、これを利用すると簡単です。

Gmailアプリの一覧/詳細はMaster/Detailパターンです。 06.png