2011年10月8日土曜日

Chapter15: 画面用javaファイルの簡単な説明

前回までで、とりあえずレイアウトの実践編は終わりにして、あとはちょっとJavaファイルの説明をしようと思います。とはいっても、あくまでもプログラムをガリガリ書くためということではなく、画面を増やしたりするときのために、必要な知識程度として、です。

なお、説明するのは、たったこれだけの量なので、大丈夫だと思います。
これは、プロジェクトを作った時点で自動的に作られているソースと同じ量です。
public class Chapter11Activity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chapter11);
    }
    // 省略
}


Activity(画面用ファイル)
Activityとは、画面用のクラスのことです。画面用のJavaファイルは、全てActivityクラスを継承しています。継承とは、指定しているクラスの機能を受け継ぐことを言います。機能(メソッド)の内容を書き換えたり、追記したり、新しい機能を追加したりします。
クラスを継承する場合は、extendsで指定します。
public class Chapter11Activity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chapter11);
    }
    // 省略
}
とはいっても、新しく画面を追加したいときは、真っ新なファイルを作って、全部書かないといけないわけではありません。Eclipseでファイルを作成した時点で、かなり書いてくれます。

Javaファイル(Activity)の作成方法
まず、パッケージ上で右クリックして、新規 > クラスを選択します。
その後、名前に画面用ファイルの名前を記述します。
今回はTestActivityと書きましたが、別に~Activityで終わる必要はありません。
その後、スーパークラスを指定します。スーパークラスとは、継承元のクラスのことです。今回はActivityを継承します。基本的に指定する場合は、パッケージ名 + クラス名になるのですが、覚えていられないので、Eclipseの力を借ります。アシストです。
Activiくらいまで打った時点で、Ctrl + Spaceを押すと、ズラッと候補が出てきます。Activityを選択しましょう。その後、完了を押します。
これだけです。


次は、onCreateメソッドの説明します。

onCreateメソッド
onCreateメソッドとは、Activityが画面を作る際に自動的に呼ばれるメソッドです。敢えてJavaScriptで例えるならば、Window.onLoadメソッドみたいなものと解釈してください。jQueryで言えば、readyメソッドです(細かい意味まで問われると全然違いますが。読み込み完了後に呼ばれるので)。

継承元のメソッドを上書きする場合は、@Overrideという記述が要ります。
onCreateメソッドは基本的にこの形なので、このままコピー&ペーストしてもらって構いません。

public class Chapter11Activity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chapter11);
    }
    // 省略
}
Androidに限らずですが、アプリケーションにはライフサイクルがあります。アプリが起動してから終了するまで(一時停止からの復帰含む)に、自動的に呼ばれるメソッドがあります。単に画面の確認をしたいだけだったら、onCreateメソッドだけ覚えておけばいいです。

ライフサイクルについて深く学びたい場合は、TechBoosterさんのライフサイクルの図解を見るとよいでしょう。

では、次にonCreateメソッドの中で何をしているかを説明します。

onCreateメソッドの中でレイアウトファイルを指定
onCreateメソッドの中は2行しかないですね。画面を表示するだけだったら、実はこれだけでよいのです。
public class Chapter11Activity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.chapter11);
    }
    // 省略
}
4行目では、親クラス(ここではActivity)のonCreateメソッドを呼び出しています。この処理は必須です。まぁ色々とやってくれてるんだなぁと思ってください(私もそう思ってます)。なお、superとは、作成のときにスーパークラスという表現があったと思いますが、親クラスを示す特別な変数です。Javaでプログラムしていると、ちょくちょく登場します。

5行目で、この画面で使用するレイアウトXMLを指定しています。setContentViewとは、レイアウトを指定するActivity固有の命令(メソッド)です。ここでは、R.layout.chapter11を指定していますが、これは、/res/layout/chapter11.xmlのことを指します。

これだけです。省略している部分はメニューボタンを押したときに表示されるメニューの動作についてのプログラムなので、あとは省略して、別の機会に取扱います。

以上で、実践編(1)は終わりです。お疲れ様でした。
そして、ありがとうございました。

また実践編(2)でお会いしましょう。

2011年10月7日金曜日

Chapter14: スタイル適用の答え合わせ

Chapter13はできたでしょうか?
スタイルをまとめるというのは、CSSを書く感覚と同じなので、理解しやすかったのではないでしょうか?
では、コードを見てみましょう。Sample03プロジェクトの/res/values/sample_styles.xmlを開いてください。
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="SampleTopBtnPort">
        <item name="android:layout_width">90dip</item>
        <item name="android:layout_height">90dip</item>
        <item name="android:adjustViewBounds">true</item>
    </style>
</resources>
スタイルは、styleタグで定義します。
name属性がCSSのクラス名と同じと思ってください。
各スタイルの定義自身は、itemタグで設定します。
itemタグのname属性に、Viewの属性名を記述し、値を定義します。
敢えてCSSっぽく書くと、
.SampleTopBtnPort {
    android:layout_width: 90dip;
    android:layout_height: 90dip;
    android:adjustViewBounds: true;
}
という感じでしょうか。

これをViewに適用すると、以下のようになります。
/res/layout/chapter14.xmlの一部を抜粋
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="top|center_horizontal"
    android:layout_marginBottom="10dp">
    <ImageView
        android:src="@drawable/regist"
        android:layout_marginRight="10dp"
        style="@style/SampleTopBtnPort" />
    <ImageView
        android:src="@drawable/manage"
        android:layout_marginRight="10dp"
        style="@style/SampleTopBtnPort" />
    <ImageView
        android:src="@drawable/photo_book"
        style="@style/SampleTopBtnPort" />
</LinearLayout>
ImageViewのstyle属性に@style/SampleTopBtnPortを指定したことで、だいぶすっきりした見た目になったかと思います。

Chapter13: スタイルにまとめてみる

さて、Chapter12はクリアできたでしょうか?
以下のような画面になっていればOKです。
次は、見た目は変わらないまま、スタイルを作ってみましょう。
スタイルとは、CSSみたいなもので、レイアウトXML内で使うViewの属性をまとめたものです。スタイルを使うことで、レイアウトの修正を簡単にすることができますし、ソースの可読性が上がります。


コードレビュー

では、コードを見てみましょう。Sample03プロジェクトの/res/layout/chapter13.xmlを開いてください。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/back_img_repeat">
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="20dp"
        android:paddingBottom="20dp">
        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/logo"
            android:adjustViewBounds="true"
            android:layout_centerInParent="true" />
    </RelativeLayout>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical"
        android:gravity="bottom"
        android:layout_marginBottom="10dp">
        <!-- 
            ImageViewで定義している属性をstyleに書き換えてください。
            ファイル名はstyles.xml
            style名はTopBtnPortで作成してください。
         -->
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="top|center_horizontal"
            android:layout_marginBottom="10dp">
            <ImageView
                android:src="@drawable/regist"
                android:layout_marginRight="10dp"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:adjustViewBounds="true" />
            <ImageView
                android:src="@drawable/manage"
                android:layout_marginRight="10dp"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:adjustViewBounds="true" />
            <ImageView
                android:src="@drawable/photo_book"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:adjustViewBounds="true" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="top|center_horizontal">
            <ImageView
                android:src="@drawable/ranking"
                android:layout_marginRight="10dp"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:adjustViewBounds="true" />
            <ImageView
                android:src="@drawable/about"
                android:layout_marginRight="10dp"
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:adjustViewBounds="true" />
            <View
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:adjustViewBounds="true" />
        </LinearLayout>
    </LinearLayout>
    <RelativeLayout
        android:id="@+id/adArea"
        android:layout_width="fill_parent"
        android:layout_height="50dp">
        <ImageView
            android:src="@drawable/nail_banner"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:layout_centerInParent="true" />
    </RelativeLayout>
</LinearLayout>
Chapter12の答え合わせですが、ここではボタンでなくImageViewを使っています。ImageButtonというViewもあるのですが、ボタン用の縁などがつくので、そういうものがいらない場合は、ImageViewで作ってしまったほうが手っ取り早いと思っています。

75行目のViewですが、ここでは表示する画像がないので、敢えて何も表示しないViewを配置しています。何も表示しないViewを配置するというのも、テクニックになってきます(最初思いつきませんでしたが、他の方のソースを見たりして、こういう方法もあるのかと気づきました)。

Chapter13の課題の「スタイルにまとめてみる」ですが、参考になるソースは、/res/layout/chapter14.xmlと、/res/values/sample_styles.xmlになります。参考にして挑戦してみてください。

Chapter12: ボタンを表示させる

さて、Chapter11はクリアできたでしょうか?
以下のような画面になっていればOKです。
次はこの画面にボタンを表示させます。
ボタンといっても、コスメマネージャーの場合はImageViewを使って画像を表示させています。
以下のような画面になります。
課題については、Chapter12のレイアウトファイル内に書かれています。


コードレビュー

では、コードを見てみましょう。Sample03プロジェクトの/res/layout/chapter12.xmlを開いてください。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/back_img_repeat">
    <!-- ロゴを入れるRelativeLayout -->
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="20dp"
        android:paddingBottom="20dp">
        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/logo"
            android:adjustViewBounds="true"
            android:layout_centerInParent="true" />
    </RelativeLayout>
    <!-- メニューを入れるLinearLayout -->
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="top|center_horizontal"
            android:layout_marginBottom="10dp">
            <!-- 
                ImageViewを3つ使ってボタンを作成してください
                srcは
                @drawable/regist
                @drawable/manage
                @drawable/photo_book
                を使ってください。
                layout_widthは90
                layout_heightは90
                adjustViewBoundsはtrue
                を指定すること。
                他に使う属性もあります。
             -->
        </LinearLayout>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="top|center_horizontal">
            <!-- 
                ImageViewを2つ使ってボタンを作成してください
                srcは
                @drawable/ranking
                @drawable/about
                を使ってください。
                layout_widthは90
                layout_heightは90
                adjustViewBoundsはtrue
                を指定すること。
                他に使う属性もあります。
                また、もう1つViewを追加して見た目を整えてください。
             -->
        </LinearLayout>
    </LinearLayout>
    <!-- フッター(広告エリア)など -->
    <RelativeLayout
        android:id="@+id/adArea"
        android:layout_width="fill_parent"
        android:layout_height="50dp">
        <ImageView
            android:src="@drawable/nail_banner"
            android:layout_width="fill_parent"
            android:layout_height="50dp"
            android:layout_centerInParent="true" />
    </RelativeLayout>
</LinearLayout>
Chapter11の答え合わせですが、ハイライトしている部分がそうです。
ImageViewで画像を指定する場合、@drawable/[ファイル名]を使います。

余談ですが、このファイルは、/res/drawable-hdpiに置いています。
いろんな解像度に対応しようと思ったら、drawable-****のすべてに画像を置くべきですが、hdpiの画像のみを置いています。 優先順位的に画像が使われるので、mdpiの端末でも、drawable-mdpiに同名のファイルがない場合はdrawable-hdpiにある画像が使われます。 全ての解像度の画像を準備しようと思うと、大変ですし、アプリ自体のファイルサイズも大きくなるので、表示が合わない素材だけを、 特定のフォルダに置くようにしましょう。

 また、デフォルトだとdrawableのフォルダのみ-hdpiや-mdpiという指定がありますが、実はlayoutファイルでもこのような指定をすることができます。詳細は今回は書きませんが、Android Developersの開発ガイドのマルチスクリーンのページを見れば参考になるかと思います。

Chapter12の解答はChapter13に書いてあるので、わからない場合はそちらを見ながら書いてみましょう。

2011年10月6日木曜日

Chapter11: ロゴとフッターを表示させる

さて、Sample03のインポートは終わっているでしょうか?
「タイトルバーを消す」をしている人はもうしているかもしれません。まだの人は、「Sample03プロジェクトを公開しました」より、インポートしてください。

今回の課題からは、実践方式になっています。
今までは基本的にソースコードを読んでもらう方式でしたが、手を動かさないとなかなか覚えられないと思いますので、そうしてみました。
Chapter11の完成コードがChapter12に、Chapter12の完成コードがChapter13に、Chapter13の完成コードがChapter14になっています。

では、Chapter11の最初の画面を見てみましょう。
Sample03アプリを起動しましょう。最初の画面は、完成予定画面です。メニューボタンを押して、chapter11をタップしてみましょう。以下の画面が表示されます。

背景だけ適用されているプレーンな画面です。
Chapter11では、ロゴとフッターをつけてもらいます。
完成イメージは以下になります。
課題はコード内に書かれていますが、コードのみ置いておきます。
Chapter11自体の答え合わせはChapter12で行います。


コードレビュー

では、コードを見てみましょう。Sample03プロジェクトの/res/layout/chapter11.xmlを開いてください。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/back_img_repeat">
    <!-- ロゴを入れるRelativeLayout -->
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="20dp"
        android:paddingBottom="20dp">
        <!-- ImageViewを使って@drawable/logoを入れてください -->
    </RelativeLayout>
    <!-- メニューを入れるLinearLayout -->
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">
    </LinearLayout>
    <!-- フッター(広告エリア)など -->
    <RelativeLayout
        android:id="@+id/adArea"
        android:layout_width="fill_parent"
        android:layout_height="50dp">
        <!-- ImageViewを使って@drawable/nail_bannerを入れてください -->
    </RelativeLayout>
</LinearLayout>
課題の行をハイライトしています。 回答はChapter12になるので、chapter12.xmlを開いて参考にしてもらっても構いませんが、できればコピペしないでください。

タイトルバーを消す方法

Chapter11にしようかと思いましたが、あまりにも簡単だし、汎用的な内容でもあるので、ChapterではなくTips扱いにします。

Sample03プロジェクトで、コスメマネージャーのトップページを作るというのを題材に扱おうとしていますが、トップページは、アプリによりますが、タイトルバーを消したりする場合があります。コスメマネージャーはトップにロゴがあるので、タイトルバーを消しています。

そこで、タイトルバーを消す方法です。
サンプル画面を見てみましょう。

タイトルバーを消すのは、レイアウトのXMLファイルからではできません。できるのはAndroidManifest.xmlファイルで、です。
AndroidManifest.xmlファイルは、Androidで使うAPIについて定義したり、使う画面用Javaファイルの定義をしたり、アプリのバージョン情報を書いたりする設定ファイルです。

アプリで統一したいテーマを定義する場合はapplicationタグでテーマ属性を定義しますが、
画面(Activity)毎にテーマを設定することも可能です。
画面Aではタイトルバーを表示したいが、画面Bでは消したいということもありますから、今回の例ではActivity単位で消してみます。


コードレビュー

ではレイアウトのコードを見てみましょう。 Sample03プロジェクトの/AndroidManifest.xmlを開いてください。
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.okolabo.android.sample03"
    android:versionCode="1"
    android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />
    <application
        android:icon="@drawable/icon"
        android:label="@string/app_name">
        <activity
            android:name=".SampleActivity"
            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=".Chapter11Activity"
            android:theme="@android:style/Theme.NoTitleBar" />
        <activity
            android:name=".Chapter12Activity"
            android:theme="@android:style/Theme.NoTitleBar" />
        <activity
            android:name=".Chapter13Activity"
            android:theme="@android:style/Theme.NoTitleBar" />
        <activity
            android:name=".Chapter14Activity"
            android:theme="@android:style/Theme.NoTitleBar" />
    </application>
</manifest>
最初のactivityタグのandroid:theme属性で、androidがデフォルトで持っているテーマを呼び出しています。android:themeを何も指定しない場合、

@android:style/Theme

が適用されます。今回はタイトルバーを消したかったので、

@android:style/Theme.NoTitleBar

を指定しています。また、タイトルバーだけでなく、ステータスバーも消してフルスクリーンにしたい場合は、

@android:style/Theme.NoTitleBar.FullScreen

を指定します。黒めのテーマを使う場合は@android:style/Theme.Black系を、白めのテーマを使う場合は、@android:style/Theme.Light系を使います。基本の背景色や、メニューボタンを押して出てくるメニューの色などが変わるので、プレーンな感じでいい場合は好きなほうをテーマとして選びましょう(デフォルトは黒系)

なお、ここでは詳しくは解説しませんが、テーマは継承できます。わかりやすくいうと、デフォルトのCSSを使って、気に入らないところだけ自分で上書きして新しいテーマを作ることができるということです。1から全部書かなくてもよいですし、全部自分で書くとAndroidアプリケーションとして他アプリとしての統一性がなくなるので、基本的にはテーマを継承して新しいテーマを定義したほうがよいでしょう。

Sample03プロジェクトを公開しました

前回までで、Sample02のプロジェクトの内容が終わりました。
 次のプロジェクトを準備してあるので、Sample03プロジェクトをダウンロードしてインポートしてください。やり方は、Eclipseでプロジェクトをインポートする(zipのまま)です。ダウンロードするURLの部分だけ、読み替えてください。よろしくお願いします。

Sample03プロジェクトへのリンク(github)

Sample03で扱う内容は、以下の通りです。
今回は著者が公開しているAndroidアプリの「コスメマネージャー」のトップ画面を作ります。

  • タイトルバーを消す
  • (Chapter11)ロゴとフッターを表示させる
  • (Chapter12)ボタンを表示させる
  • (Chapter13)スタイルを作成する
  • (Chapter14)スタイル適用の答え合わせ
  • (Chapter15)画面用javaファイルの簡単な説明