2011年5月19日木曜日

Android Tab Layout の Icon についてのメモ

Tab Layoutのアイコンは低、中、高解像度のデバイス用にそれぞれアイコンを用意する。
アイコンのサイズ等の仕様はAndroid Developers の Icon Design GuidelinesTab Icons にかかれている。これによると


低解像度(ldpi) 中解像度(mdpi) 高解像度(hdpi)
アイコンサイズ 24 x 24 px 32 x 32 px 48 x 48 px
描画領域のサイズ 22 x 22 px 28 x 28 px 42 x 42 px
アイコンの置き場所
Android 2.0以上
res/drawable-ldpi-v5 res/drawable-mdpi-v5 res/drawable-hdpi-v5
アイコンの置き場所
Android 2.0未満
res/drawable-ldpi res/drawable-mdpi res/drawable-hdpi

アイコンの絵はサイズギリギリではなく、周囲に save margine として余白を置くよう推奨している。また絵が四角型の場合はバランスを取るためにもう少し小さくするように推奨している。

Androidでは2.0からタブアイコンのスタイルが大きく変わったので(どう変わったのかはよく知らない)、それぞれのアイコンの置き場所を表の様に分けている。注意点として Manifestファイルの <uses-sdk> の属性 android:targetSdkVersion を 5 以上(Android 2.0以上)に設定すること。たぶんこれでアイコンが上記の2つの場所に分けておかれていることを(Android 2.0以上の)システムが認識できる。

実際に(Illustrator、inkscape等で)アイコンを描く時には、各解像度のサイズの整数倍のサイズで書くように推奨している。 24, 32, 48 さらにメニュー用アイコンで使う72 px を考慮すると、これらの最小公倍数は lcm(24, 32, 48, 72) = 144 となる。よって144 x 144 px の整数倍のサイズの画像を作成し(例えば 864 x 864 px)、これを各サイズに縮小するよう勧めている。

2011年5月17日火曜日

Tab Layoutを使ってみる

Tab Layoutの使い方のメモ。ちょっと未来の自分のために(^_^;
内容は Android Developers の Tutorial と同じ。これを自分に分かりやすく(日本語で)書いたもの。

タブを使うときのレイアウトは以下のような構成になる。

TabHost <- root node, 一番上の親
    LinearLayout <- 以下の子を縦に配置する
        TabWidget <- タブが表示される領域
        FrameLayout <- タブによって切り替えられたコンテンツが表示される領域

まず最初に、メインのレイアウトファイル main.xml を以下の様につくろう。


<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:padding="5dp">
        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:padding="5dp" />
    </LinearLayout>
</TabHost>

ポイントは LinearLayout の orientation を "vertical" にすること、また TabWidget の id は "@android:id/tabs"、コンテンツを表示する FrameLayout の id は "@android:id/tabcontent" とする必要がある。これはこの id を使って親の TabHost がこれらを認識するため。

このサンプルでは3つの Activity をタブによって切り替える。外観は次の様になる。


お次はこれらの Activity を作ろう。
Activityは
  • ArtistsActivity
  • AlbumsActivity
  • SongsActivity
それぞれのソースコードは
ArtistsActivity.java:

package test.hellotabwidget;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ArtistsActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView textview = new TextView(this);
        textview.setText("This is the Artists tab");
        setContentView(textview);
    }
}

AlbumsActivity.java:

package test.hellotabwidget;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class AlbumsActivity extends Activity {
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView textview = new TextView(this);
        textview.setText("This is the Albums tab");
        setContentView(textview);
    }
}

SongsActivity.java:

package test.hellotabwidget;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class SongsActivity extends Activity {
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView textview = new TextView(this);
        textview.setText("This is the Songs tab");
        setContentView(textview);
    }
}

それぞれの内容はほとんど同じで、表示する文字列だけが異なる。またこれらの Activity はここでは簡単のためにレイアウトファイル(*.xml)は使わない。直接 TextView を生成してコンテンツとして設定している。

次はタブに表示するアイコン。これは先のTutorialからコピーしたものを用いる。面倒なので3つのタブ全て同じアイコンとする。実際にはそれぞれに別のアイコンを用意する。
タブが選択されたときのアイコン(ic_tab_artists_grey.png)
非選択時のアイコン(ic_tagb_artists_white.png)

これらのアイコンを res/drawable/ に保存する。
さらに以下の xml ファイルを同じ res/drawable/に保存し、タブの選択・非選択時のアイコン画像を指定する。

ArtistsActivityのタブには
ic_tab_artists.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- When selected, use grey -->
    <item android:drawable="@drawable/ic_tab_artists_grey"
          android:state_selected="true" />
    <!-- When not selected, use white-->
    <item android:drawable="@drawable/ic_tab_artists_white" />
</selector>

同様に AlbumActivity には ic_tab_albums.xmlを、SongsActivity には ic_tab_songs.xml 用意する。内容はic_tab_artists.xml とまったく同じでよい(実際にはそれぞれに使用するアイコンを別に指定する)。

次はユーザーがアプリ起動時に呼び出す一番上の Activity を作成する。
HelloTabWidget.java:

package test.hellotabwidget;

import android.app.TabActivity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TabHost;

public class HelloTabWidget extends TabActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Resources res = getResources(); // Resource object to get Drawables
TabHost tabHost = getTabHost();  // The activity TabHost
TabHost.TabSpec spec;  // Resusable TabSpec for each tab
Intent intent;  // Reusable Intent for each tab

// Create an Intent to launch an Activity for the tab (to be reused)
intent = new Intent().setClass(this, ArtistsActivity.class);

// Initialize a TabSpec for each tab and add it to the TabHost
spec = tabHost.newTabSpec("artists").setIndicator("Artists",
res.getDrawable(R.drawable.ic_tab_artists))
.setContent(intent);
tabHost.addTab(spec);

// Do the same for the other tabs
intent = new Intent().setClass(this, AlbumsActivity.class);
spec = tabHost.newTabSpec("albums").setIndicator("Albums",
res.getDrawable(R.drawable.ic_tab_albums))
.setContent(intent);
tabHost.addTab(spec);

intent = new Intent().setClass(this, SongsActivity.class);
spec = tabHost.newTabSpec("songs").setIndicator("Songs",
res.getDrawable(R.drawable.ic_tab_songs))
.setContent(intent);
tabHost.addTab(spec);

tabHost.setCurrentTab(2);
}
}

ここでは通常の Activity ではなく TabActivity を継承する。
getTabHost() で TabHost を取得し、 newTabSpec(String) で TabHost.TabSpec を作成しそれぞれのタブの特性を設定する。そして addTab(TabSpec) でそれぞれのタブを追加していく。
最後にsetCurrentTab(int)で最初に表示されるタブをインデックスで指定する。

最後にManifestにこれらのActivityを追加するのを忘れないこと。
AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="test.hellotabwidget"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="6" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".HelloTabWidget"
 android:label="@string/app_name"
           android:theme="@android:style/Theme.NoTitleBar">
             <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
           
        <activity android:name=".ArtistsActivity" />
        <activity android:name=".AlbumsActivity" />
        <activity android:name=".SongsActivity" />
    </application>
</manifest>

精度

スマートフォンを操作したりしているときに歩数計アプリが誤動作しないように、一定時間カウントが続かないと歩いてると見なさない様にした。これでずいぶん誤動作が減ったんだけど、家の中でちょっと歩いたりとかがカウントされにくい。
難しいな~。

2011年5月16日月曜日

歩数計アプリ

歩数計のAndroidアプリを作っている。とりあえず動作確認のプロトタイプは作っていてまずまず動作する。次は公開するために、UIをきちんと作り込んだり、搭載する機能を決めたりする予定。6月半ばには公開できるかな?