Android Developer Blog によると、ScrollView の fillViewport の解説が、

ROMAIN GUY さんのブログで解説されていたようです。

http://www.curious-creature.org/2010/08/15/scrollviews-handy-trick/

 

参照元のブログによると、

スクロールバーを使って、画面の高さより大きいレイアウトを表示させるには、

スクロールさせたいビューの親に「ScrollView」に配置します。

 

これにより、下図のように、配置したレイアウトの高さが、画面の高さより大きい場合、

スクロールバーが表示され、(スクロールさせることにより)レイアウト全体を表示させることができます。

※この結果、一番下のスクロール位置では、最下段に配置したボタンが画面下部に配置されます

ok_textview_long_top.png ok_textview_long_bottom.png

 

一方、下図のように、配置したレイアウトの高さが、画面の高さより小さい場合には、

「ScrollView」の高さ設定が、android:layout_height="fill_parent" であっても、

「ScrollView」の高さは、親ビューであるアクティビティーにフィットされず、子ビューの高さで表示されてしまいます。

ng_textview_short.png

 

上記のような表示を意図している場合には、このままで良いのですが、

下図のように、「ScrollView」の高さを、親ビューであるアクティビティーにフィットさせ、

レイアウト最下段を、画面下に配置させたい場合には、

「ScrollView」の高さ設定を、android:fillViewport="true" とする必要があるようです。

ok_textview_short.png

 

※ちなみに、この fillViewport 属性については、これまでドキュメント化されていなかったそうです^^;

 

ソースコード(原文より引用)

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scroller"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:fillViewport="true" >
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="6dip"
            android:paddingRight="6dip"
            android:paddingTop="6dip"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="Welcome to My Application" />

        <View
            android:layout_width="fill_parent"
            android:layout_height="1dip"
            android:background="#ff106510"
            android:layout_marginLeft="6dip"
            android:layout_marginRight="6dip"
            android:layout_marginTop="6dip"
            android:layout_marginBottom="12dip" />

        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1.0"

            android:paddingLeft="6dip"
            android:paddingRight="6dip"
            android:paddingBottom="6dip"

            android:text="@string/hello" />

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"

            android:background="@android:drawable/bottom_bar"
            android:gravity="center_vertical">
            <Button
                android:layout_width="0dip"
                android:layout_weight="1.0"
                android:layout_height="wrap_content" 

                android:text="Accept" />
            <Button
                android:layout_width="0dip"
                android:layout_weight="1.0"
                android:layout_height="wrap_content" 

                android:text="Refuse" />
        </LinearLayout>
    </LinearLayout>
</ScrollView>

Input Method Engine(IME)表示時に、アクティビティーを伸縮させる方法について。

 

例えば、下図のような(テキスト、エディット、ボタンの順に配置された)レイアウトを例に説明します。

IME_OFF.png

 

画面中央のエディットボックスにフォーカスをあてると、IME(ここでは Simeji) が表示されるのですが、

通常では、下図のように画面下半分が隠れてしまい、アクティビティー全体が表示されません。

この結果、画面下部に配置したボタンが操作できなくなってしまいます。

IME_ON_NG.png

 

そこで、IME 表示時にアクティビティーを伸縮させるには、

AndroidManifest.xml ファイルの対象のアクティビティに「android:windowSoftInputMode="adjustResize"」を指定します。

すると、下図のように IME 以外の残りの領域が、アクティビティー全体にレイアウトされます。

この結果、アクティビティー画面下部に配置していたボタンを操作することができます。

IME_ON_OK.png

 

(上記説明で使用した)サンプルソースコード

  • AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...>
    <application android:icon="@drawable/icon"
        android:label="@string/app_name">
        <activity android:name=".UpdateStatusActivity"
            android:windowSoftInputMode="adjustResize" />
    </application>
    ...
</manifest>

 

  • res/layout/update_status.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">
    <TextView android:id="@+id/textview_remain_status_length"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="right" />
    <EditText android:id="@+id/edittext_status_text"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1"
        android:gravity="top"
        android:hint="@string/whats_happening" />
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button android:id="@+id/button_update"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/update" />
        <Button android:id="@+id/button_cancel"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/cancel" />
    </LinearLayout>
</LinearLayout>

AndroidSDKDevelopmentRecipe.jpg

 

著者の塚田様のご厚意により秀和システム様より献本御礼。

 

本書「Android SDK 開発レシピ」は、「Android 名古屋 つくる部」や「Facetter Camera」でお馴染みの
塚田(gabu)様による逆引き形式の開発レシピ本

収録された104のレシピは、どれも実践的なものばかりであり、解説とサンプルコードを読むことで、容易に理解することができる。

また、各レシピは独立した内容で構成されているため、目次にて興味をもったレシピから読むこともできるほか、
物理的な本のサイズが、A5サイズ・312ページのため、片手で読むこともでき、携帯しやすいサイズとなっている。
このため、ちょっとした時間に読むことができ、通勤電車などで重宝しそうだ。

内容的には、これまでの入門本のような Java や Eclipse などの開発環境の構築の内容を含まないため、
すでに Android 本を持っている方々にとっても、二冊目として手元に残しておきたい一冊である。

なお、発売日は2010年8月10日(地域によって異なる)であり、以下のリンク先からも購入(予約)可能である。

 

Amazon

 

目次

  • Chapter 1 開発環境のレシピ

    レシピ 001 実機とエミュレータで動作を切り替える
    レシピ 002 端末情報で動作を切り替える
    レシピ 003 デバッグ時のみ有効な処理を作る
    レシピ 004 新規クラス作成時にヘッダコメントを挿入する
    レシピ 005 端末内のファイルを編集する
    レシピ 006 コマンドラインからビルドする
    レシピ 007 ユニットテストを行う
    レシピ 008 ユニットテストでUIのテストを行う

 

  • Chapter 2 基本レシピ

    レシピ 009 ユニークなファイル名を生成する
    レシピ 010 アプリケーションの終了を検知する
    レシピ 011 自動的に画面ロックしないようにする
    レシピ 012 URLエンコードする
    レシピ 013 Listをランダムに並べ替える
    レシピ 014 クリップボードを使う
    レシピ 015 プリファレンスにデータを保存する
    レシピ 016 XMLをパースする
    レシピ 017 文字列からMD5を取得する
    レシピ 018 ローカライズ
    レシピ 019 パスワードを安全に保存する
    レシピ 020 起動パスワードをつける
    レシピ 021 設定画面を作成する
    レシピ 022 ZIPファイルを解凍する
    レシピ 023 JSON形式のデータを扱う
    レシピ 024 正規表現を使う
    レシピ 025 インストールされているアプリの一覧を取得する
    レシピ 026 コンタクトリストを取得する

 

  • Chapter 3 UIのレシピ

    レシピ 027 画面の回転をロックする
    レシピ 028 EditTextを選択状態にする
    レシピ 029 プログレスダイアログを表示する
    レシピ 030 端末の解像度に合わせて画像を表示する
    レシピ 031 拡大されても綺麗な画像(9-patch)を作る
    レシピ 032 Buttonに背景画像(9-patch)を使う
    レシピ 033 Buttonの状態によって背景画像を変える
    レシピ 034 アラート内にEditTextを表示する
    レシピ 035 アラート内にWebViewを表示する
    レシピ 036 WebViewで用意したHTMLを表示する
    レシピ 037 WebViewでカバーフローを作る
    レシピ 038 ジェスチャーを認識する
    レシピ 039 WebViewをジェスチャーで操作する

 

  • Chapter 4 ListViewのレシピ

    レシピ 040 所定の位置までスクロールさせる
    レシピ 041 表示内容をカスタマイズする
    レシピ 042 リンクを設定する
    レシピ 043 クリックを検知する
    レシピ 044 長押しを検知する
    レシピ 045 最後までスクロールしたことを検知する
    レシピ 046 次のX件を読み込む

 

  • Chapter 5 画像のレシピ

    レシピ 047 画像を任意のサイズにリサイズする
    レシピ 048 画像を任意のサイズで切り取る
    レシピ 049 アニメーションGIFを簡単に表示する
    レシピ 050 ImageViewをアニメーションする
    レシピ 051 ImageViewに反射エフェクトをつける
    レシピ 052 点を描画する
    レシピ 053 直線を描画する
    レシピ 054 四角形を描画する
    レシピ 055 円を描画する
    レシピ 056 楕円を描画する
    レシピ 057 弧を描画する
    レシピ 058 パスを描画する
    レシピ 059 Bitmapに描画する
    レシピ 060 拡大縮小可能なImageView

 

  • Chapter 6 マルチメディアのレシピ

    レシピ 061 音声ファイルを再生する
    レシピ 062 マイクから録音する
    レシピ 063 音を感知するスイッチを作る
    レシピ 064 カメラの映像にビューを重ねる
    レシピ 065 ギャラリーから写真を選択する
    レシピ 066 動画を撮影する
    レシピ 067 動画を再生する
    レシピ 068 再生中の動画にビューを重ねる

 

  • Chapter 7 ハードウェアのレシピ

    レシピ 069 シェイクを検知する
    レシピ 070 バッテリーの状態を取得する
    レシピ 071 近接センサーを使う
    レシピ 072 明るさセンサーを使う
    レシピ 073 位置情報を取得する
    レシピ 074 方位を取得する
    レシピ 075 地磁気センサーを使う
    レシピ 076 端末の向きでレイアウトを切り替える

 

  • Chapter 8 ネットワークのレシピ

    レシピ 077 ネットワークの接続状況を判定する
    レシピ 078 Webサービスから天気情報を取得する
    レシピ 079 メールを送信する

 

  • Chapter 9 データベース(SQLite)のレシピ

    レシピ 080 データベースをオープンする
    レシピ 081 テーブルを作成する
    レシピ 082 レコードを追加・更新・削除する
    レシピ 083 レコードを検索する
    レシピ 084 テーブルを変更する
    レシピ 085 検索結果をListViewに表示する

 

  • Chapter10 インテントのレシピ

    レシピ 086 ブラウザを呼び出す
    レシピ 087 電話を呼び出す
    レシピ 088 カメラを呼び出す
    レシピ 089 動画を撮影するアプリを呼び出す
    レシピ 090 ボイスレコーダーを呼び出す
    レシピ 091 音声認識を呼び出す
    レシピ 092 特定のアプリを呼び出す

 

  • Chapter11 外部連携のレシピ

    レシピ 093 音楽データを取得する
    レシピ 094 標準の音楽アプリにアクセスする
    レシピ 095 Tumblrに写真をアップする
    レシピ 096 Evernoteと連携する
    レシピ 097 AdMobの広告を組み込む
    レシピ 098 Googleドキュメントの一覧を取得する
    レシピ 099 Googleドキュメントのファイルをダウンロードする
    レシピ 100 Googleドキュメントに文書を保存する
    レシピ 101 Googleカレンダーから予定を取得する
    レシピ 102 Twitter4JでxAuthを使う

 

  • Chapter12 ホーム画面のレシピ

    レシピ 103 ウィジェットを作る
    レシピ 104 ライブ壁紙を作る

 

あわせて読みたい

アプリケーションのプログラム内からデバイスへ画像を追加した際、

そのままでは、ギャラリー(標準の画像ビューワー)に表示(反映)されません。

解決するには、以下のように MediaScannerConnection クラスを使用するか、ContentResolver クラスを使用します。

※サンプルコードでは両方のコードを記述していますが、実際には、どちらか一方でOKです
 HTC Desire + Android 2.2 の環境でのみ動作確認

 

サンプルコード

String title = "test";
String fileName = title + ".jpg";
String mimeType = "image/jpeg";
File file = new File(
    Environment.getExternalStorageDirectory(),
    fileName);

// MediaScannerConnection を使用する場合
MediaScannerConnection.scanFile( // API Level 8
    this, // Context
    new String[] { file.getPath() },
    new String[] { mimeType },
    null);

// ContentResolver を使用する場合
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues(7);
values.put(Images.Media.TITLE, title);
values.put(Images.Media.DISPLAY_NAME, fileName);
values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(Images.Media.MIME_TYPE, mimeType);
values.put(Images.Media.ORIENTATION, 0);
values.put(Images.Media.DATA, file.getPath());
values.put(Images.Media.SIZE, file.length());
contentResolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);

 

参考

  • ギャラリーへの画像反映方法について ・・・要グループアカウント
  • MessageView.java
    ※上記では、MediaScannerConnectionクラスのstaticなscanFileメソッドを使用していましたが、
     MessageView.java の MediaScannerNotifier クラスのように、
     MediaScannerConnectionClient インターフェースを使用する方法もあります
  • WEB+DB PRESS Vol.57」の「第5章 カメラ本格活用アプリを作ろう P.51」にも解説がありました
  • @gabu さん、@thorikawa さん、有難うございました

標準のカメラアプリケーションでは、カメラで撮影した画像のファイル名を重複しないようにするために、

以下のように、日時をキーとしてファイル名を決めているようです。

SimpleDateFormat クラスを使用すると、簡単に書式化できるんですね。

 

サンプルコード

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
    "'IMG'_yyyyMMdd_HHmmss'.jpg'");
String fileName = simpleDateFormat.format(
    new Date(System.currentTimeMillis()));

// 出力結果
// 2010年8月4日22時34分56秒の場合 -> 「IMG_20100804_223456.jpg」
Log.v("FileName", fileName); 

モデル名

Build.MODEL の値は、以下のとおりです。

  • "JN-DK01" : Android向けソフトウェア開発者向け専用端末JN-DK01
  • "IS01" : IS01 (au by KDDI)
  • "SH-10B" : LYNX SH-10B (NTT docomo)

 

エミュレーター起動オプション

JN-DK01 のエミュレーターは、標準のエミュレーターと異なる起動オプションが必要です。

※@JDK01の部分は、各々の環境に応じて読み換えてください

emulator @JNDK01 -qemu --cpu cortex-a8

 

また、エミュレーター画面を縮小するには、-scale を付加することでできます。

※以下は、75%表示の例

emulator @JNDK01 -scale 0.75 -qemu --cpu cortex-a8

 

Eclipse 上でエミュレーターのオプションを設定するには、

対象プロジェクトの「Properties」 > 「Run/Debug Settings」 > 任意のLaunch configurations >

「Edit」 > 「Target」 > 「Automatic」 > 「Additional Emulator Command Line Options」、

のエディットボックスに設定します。

configuration.png

 

エミュレーターからネットワークに接続する

2010/7/31現在、標準の設定アプリケーションからネットワーク設定を行うことができません。

しかしながら、以下のように net.dns1 プロパティに DNS サーバーのアドレスを設定することで、

この問題を回避できるようです。

※例えば、google の DNS サーバーを利用する場合

setprop net.dns1 8.8.8.8

 

あわせて読みたい

java.security パッケージに含まれる SecureRandom クラスを使用すると、

任意の長さを指定してランダムバイト配列を取得することができます。

 

サンプルソースコード

byte bytes[] = new byte[20];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(bytes);
// または
bytes = secureRandom.generateSeed(20);

 

参考

SQLiteDatabase を使って Bitmap 画像を読み書きしてみました。

データ型に、Bitmap 型は存在しないので、Blob 型(バイナリラージオブジェクト)を使用しました。

get/set で Bitmap を読み書きできます。

 

サンプルソースコード

public class BitmapDB extends SQLiteOpenHelper {

    private static final String NAME = "bitmap.db";
    private static final int VERSION = 1;

    private static final String TABLE = "bitmap";
    private static final String _ID = "_id";
    private static final String URL = "url";
    private static final String BITMAP = "bitmap";

    private static final String[] COLUMNS = { _ID, URL, BITMAP };

    public BitmapDB(Context context) {
        super(context, NAME, null, VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE + " (" // 
                + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT," //
                + URL + " TEXT NOT NULL," //
                + BITMAP + " BLOB NOT NULL" //
                + ");");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE);
        onCreate(db);
    }

    private synchronized void setCacheAsBlob(String key, byte[] bytes) {
        boolean exist = (getCacheAsBlob(key) == null) ? false : true;
        SQLiteDatabase db = getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(URL, key);
        values.put(BITMAP, bytes);
        if (exist) {
            db.update(TABLE, values, URL + "=" + "'" + key + "'", null);
        } else {
            db.insert(TABLE, null, values);
        }
        db.close();
    }

    private synchronized byte[] getCacheAsBlob(String key) {
        byte[] bytes = null;
        final SQLiteDatabase db = getReadableDatabase();
        final Cursor cursol = db.query(TABLE, COLUMNS, URL + "=" + "'" + key
                + "'", null, null, null, null);
        if (cursol.getCount() == 1) {
            if (cursol.moveToFirst()) {
                bytes = cursol.getBlob(2);
            }
        }
        cursol.close();
        db.close();
        return bytes;
    }

    public Bitmap getBitmp(String url) {
        Bitmap bitmap = null;
        byte[] bytes = getCacheAsBlob(url);
        if (bytes != null) {
            bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        }
        return bitmap;
    }

    public void setBitmap(String url, Bitmap bitmap) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        if (bitmap.compress(Bitmap.CompressFormat.PNG, 100,
                byteArrayOutputStream)) {
            byte[] bytes = byteArrayOutputStream.toByteArray();
            setCacheAsBlob(url, bytes);
        }
    }

}

 

大量の画像が存在した場合、任意のファイルを検索して、ファイルで直接読み書きするのと、どちらが高速なんですかね?

もっとよい方法をご存じの方、お待ちしております^^;

android_market_dda.png

Android マーケットのデベロッパー販売/配布契約書(DDA)が更新されました。

 

公式の「Android Developers Blog」では、「13.1」「13.2」についてコメントが記載されていました。

http://android-developers.blogspot.com/2010/07/adjustment-to-market-legals.html

 

13. 補償

  • In Section 13.1, "authorized carriers" have been added as an indemnified party.
    法律で認められる最大限の範囲内において、
    デベロッパーは、(a)デベロッパーが本契約に違反してマーケットを使用したこと、
    および(b)デベロッパーの対象製品が他者の何らかの著作権、商標権、
    営業秘密、トレード ドレス、特許権、もしくはその他の知的財産権を侵害していること、
    または他者の名誉を毀損している、もしくは他者のパブリシティ権
    もしくはプライバシーを侵害していることから発生したあらゆる第三者からの申し立て、
    普通法上の訴訟、衡平法上の訴訟、または法的手続き、
    ならびにあらゆる損失、責任、損害、費用、および経費
    (合理的な弁護士報酬を含む)について、Google、その関連会社、
    ならびに当該各社の取締役、役員、従業員、代理人および認定携帯通信会社を防御し、
    補償し、免責することに同意します。
    →認定携帯通信会社を追加

 

  • Section 13.2 is new in its entirety, covering indemnity for payment processors for claims related to tax accrual.
    法律で認められる最大限の範囲内において、
    ディベロッパーが マーケットを通じて販売 / 配布したことから発生した
    税に関する あらゆる第三者からの申し立て、 普通法上の訴訟、衡平法上の訴訟、
    または法的手続き、ならびにあらゆる損失、責任、損害、費用、および経費
    (合理的な弁護士報酬を含む)について、
    ディベロッパーは 支払い処理業者 ( Google, または 第三者を 含む ) 、
    支払い業者の 関連会社、取締役、役員、従業員、および代理人 を防御し、
    補償し、免責することに同意します 。
    →「13.2」新設

 

また、Planet Android 経由で見つけた以下の海外サイトでは、

「3.2」「4.5」「7」についても、コメントされていました。

http://www.stealthcopter.com/blog/2010/07/google-updates-its-android-market-developer-distribution-agreement/

 

なお、新しい契約条件は、http://market.android.com/publish/ddaUpdate にアクセスすることで確認できます(要 開発者登録)。

IS01.png

IS01(JN-DK01)で電池残量更新間隔を確認した結果、

一般的な 1% 間隔ではなく、10% 間隔であることがわかりました。

つまり、システムからは、100%→90%→80%...のように、10% 間隔でのみ更新情報が届きます。

したがって、10% 分の電池を消費、または充電する時間が長い場合、

電池残量が更新されていないように感じることがあるかもしれませんが、

端末側の仕様のため、ご理解ください^^;

 

調査したアプリケーション

  • 標準の電池残量表示 (プリインストールアプリ)
  • Battery Status Free (海外アプリ)
  • Simple Battery Status (国内アプリ)

 

※他にも、海外の Milestone / DROID 端末も、電池残量更新間隔は、10% 間隔のようです

※調査に協力していただいた @lychee さん、@hyoromo さん、ありがとうございました!

 

追記

  • 2010/7/28:公式の回答でも10%間隔であることを確認できました
<<前のページへ 678910111213141516

2014年7月

    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31