2011/04/28

先月の話だけど、Titanium Mobile 1.6.1 Released です。

修正点

・iOS:XCode4(iOS4.3)に対応 ・iOS:Facebook認証の修正(iOS3.1.x系とSafari未対応機種) ・Android:JavaScriptコンパイルのUTF-8エンコーディング対応 ・Android:ActivityとWindowのライフサイクル問題修正 ・Android:Intent のフラグ対応

インタプリタ

話はそれるが、Titanium の仕組みを良くわかっていなかった。 iOSにソースが書き出されているので、てっきりソースを書き出しているのかと思っていたが、 Android では Ti のパッケージファイルを読む記述しかない。

Android も iOSもJSインタプリタで動作している

超基本的な事でした。。。

  2011/04/27

英語版、日本語版などローカライズする場合は、string.xml を分けて設定すれば良い。

日本語の場合は、values-ja というディレクトリを追加して、日本語用の string.xml を追加します。 ローカライズ

デフォルト


    Sample
    
        15sec
        30sec
        1min
        2min
        10min
        30min
    
    Memory
    SD Card
    Battery

日本語


    サンプル
    
        通常音
        バイブ
        サイレント
    
    
        15秒
        30秒
        1分
        2分
        10分
        30分
    
    本体メモリ残量
    SDカード残量
    バッテリー残量

あとは、R.string でアクセスしてバインディングしてやるだけです。

ちなみに画面お越しの際に string.xml でプロパティ化して作る癖をつけた方が、 効率的だなぁと実感しました。

  2011/04/20

画面を指で横にスライドさせる方法。 ScrollView あたりを使うのかな?と調べてみると、ViewFlipper なるものがある。

画面作成

layout/ に first.xml、second.xml、third.xml を作成し、main.xml に ViewFlipper として追加する。




    
        
        
        
    

アニメーションカスタマイズ

アニメーションは、R.anim に定義されているが、スライドを表現するには実現できないのでカスタマイズが必要となる。

以下の4ファイルを res/anim/ に作成する。 ■move_in_left.xml





■move_in_right.xml





■move_out_left.xml





■move_out_right.xml





ViewFlipper のアニメーション

[java] import android.app.Activity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.animation.AnimationUtils; import android.widget.ViewFlipper;

public class FlipperTestActivity extends Activity implements View.OnTouchListener { private ViewFlipper viewFlipper; private float firstTouch; private boolean isFlip = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    viewFlipper = (ViewFlipper) findViewById(R.id.flipper);
    viewFlipper.setAutoStart(false);
    findViewById(R.id.firstlayout).setOnTouchListener(this);
    findViewById(R.id.secondlayout).setOnTouchListener(this);
    findViewById(R.id.thirdlayout).setOnTouchListener(this);
}

public boolean onTouch(View v, MotionEvent event) {
    int x = (int)event.getRawX();
    switch(v.getId()) {
    case R.id.firstlayout:
    case R.id.secondlayout:
    case R.id.thirdlayout:
        switch(event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            firstTouch = event.getRawX();
            return true;
        case MotionEvent.ACTION_MOVE:
            if(!isFlip) {
                if(x - firstTouch > 50) {
                    isFlip = true;
                    viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.move_in_left));
                    viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.move_out_right));
                    viewFlipper.showNext();
                }
                else if(firstTouch - x > 50) {
                    isFlip = true;
                    viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.move_in_right));
                    viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.move_out_left));
                    viewFlipper.showPrevious();
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            isFlip = false;
            break;
        }
    }

    return false;
}

} [/java] View.OnTouchListener を implements して View のタッチイベントを登録する。 onTouch でタッチの状況を判別して ViewFlipper のアニメーションと画面切り替えをする。

参考サイト

ViewFlipperで簡単スライドショー

  2011/04/19

画面移動先の Activity を終了したときに、元画面で判別させて処理する方法。

何の難しい事もなかった、setResult() を設定してやるだけでした。

移動先画面の終了

[java] private function result() { Intent intent = new Intent(); intent.putExtra("ResultValue", 1); setResult(RESULT_OK, intent); finish(); }

private function cancel() { Intent intent = new Intent(); setResult(RESULT_CANCELED, intent); finish(); } [/java] startActivity() 同様、intent と Activity の定数をセットして finish() します。

元画面

[java] @Override public void onActivityResult(int requestCode, int resultCode, Intent data){ if (resultCode == RESULT_OK ) { finish(); } else if (resultCode == RESULT_CANCELED) {

}

} [/java] finish() が実行されると onActivityResult()イベントが自動的に呼ばれます。

  2011/04/19

設定ファイル保存 では SharedPreferences を利用してデータ保存したが、今回はそれに加えて PreferenceActivity を継承して設定画面を作ってみる。

ListView 項目

values/arrays.xml を作成して項目を追加する。




    
        8:00
        7:00
        6:00
        5:00
        4:00
        3:00
        2:00
        1:00
        0:00
    
    
        8
        7
        6
        5
        4
        3
        2
        1
        0
    
    
        23:00
        22:00
        21:00
        20:00
    
    
        23
        22
        21
        20
    

Preference の構造作成

xml/preference.xml を作成する。 android ここで、PreferenceScreen を追加する事で定型化された設定画面を作成する事ができる。 入れ子にすれば階層化もできます。 PreferenceScreen で設定項目をカテゴライズできます。




    
        
        
    

ListPreferenceの、entries、entryValues に arrays.xml で定義したパラメータを設定するだけ。 ここで疑問に思ったのが、

設定した値のパラメータがない

summary に値を表示できれば良いと思ったが、xml だけで動的に設定できないようだ。

という事で、プログラムソースに記述する必要がある。 かなり美しくないソースだが、とりあえず実装。 [java] import java.util.HashMap; import java.util.Map;

import android.content.SharedPreferences; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen;

public class SettingActivity extends PreferenceActivity { Preference preference; Map<String, String> scheduleStartTimes = new HashMap<String, String>(); Map<String, String> scheduleEndTimes = new HashMap<String, String>();
Preference scheduleStartPref; Preference scheduleEndPref;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preference);

    PreferenceScreen screenPref = (PreferenceScreen)findPreference("preferenceScreen");
    PreferenceCategory scheduleCategoryPref = (PreferenceCategory) screenPref.findPreference("schedulePref");

    scheduleStartPref = (Preference) scheduleCategoryPref.findPreference("schedule_start_time_key");
    String[] scheduleStartTimeValues = getResources().getStringArray(R.array.schedule_start_time_keys);
    String[] scheduleStartTimeKeys = getResources().getStringArray(R.array.schedule_start_time_values);
    for (int i = 0; i < scheduleStartTimeKeys.length; i++) {  
        scheduleStartTimes.put(scheduleStartTimeKeys[i], scheduleStartTimeValues[i]);   
    }
    loadPreference(scheduleStartPref.getSharedPreferences(), "schedule_start_time_key");

    scheduleEndPref = (Preference) scheduleCategoryPref.findPreference("schedule_end_time_key");
    String[] scheduleEndTimeValues = getResources().getStringArray(R.array.schedule_end_time_keys);
    String[] scheduleEndTimeKeys = getResources().getStringArray(R.array.schedule_end_time_values);
    for (int i = 0; i < scheduleEndTimeKeys.length; i++) {  
        scheduleEndTimes.put(scheduleEndTimeKeys[i], scheduleEndTimeValues[i]);     
    }
    loadPreference(scheduleEndPref.getSharedPreferences(), "schedule_end_time_key");
}

@Override
protected void onResume() {
    super.onResume();
    getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
}

@Override
protected void onPause() {
    super.onPause();
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
}

private SharedPreferences.OnSharedPreferenceChangeListener listener = 
    new SharedPreferences.OnSharedPreferenceChangeListener() {

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        loadPreference(sharedPreferences, key);
    }
};

private void loadPreference(SharedPreferences sharedPreferences, String key) {
    String index = sharedPreferences.getString(key, "");
    if (key.equals("schedule_start_time_key")) {
        scheduleStartPref.setSummary(scheduleStartTimes.get(index));
    }
    if (key.equals("schedule_end_time_key")) {
        scheduleEndPref.setSummary(scheduleEndTimes.get(index));
    }
}

} [/java]

onCreate されたときと設定変更後のリスナー SharedPreferences.OnSharedPreferenceChangeListener で summary に設定値を表示しています。

PreferenceActivity を継承しているので、sharedPreferences.getString() で対象の項目の設定値を取得できる。 ただここで問題なのが、entries と entryValues を別途設定していので関連付けが必要。 onCreate で 設定項目を HashMap 化してから対象のキーを判別して取得しています。 何とも力技で、もうちょっとシステマチックできそうな気がしますが。。。

参考サイト

設定画面の作り方(PreferenceActivity)Android 設定画面を作成する

  2011/04/15

Android というか Javaネタ。 ArrayList データを条件によって分類しようと考えたが、javaの基本的な事がわかっていなかった。。。

・Iterator の戻し方 ・ArrayList の多次元化(っていうのか?)

ちょっと、いい加減なサンプルかと思うが。

サンプル

[java] ArrayList schedules = getSchedules(); ArrayList<ArrayList> daySchedules = new ArrayList<ArrayList>(); for (int i = 0; i < 31; i++) { ArrayList _schedules = new ArrayList(); Iterator iterator = _schedules.iterator(); while (iterator.hasNext()) { Schedule schedule = iterator.next(); if (_schedules.date.getDate() == i) { daySchedules.add(schedule); } } daySchedules.add(daySchedules); } [/java]

Iterator の戻し方

なんて事はない。 [java] iterator.moveToFirst(); [/java] もしくは、 [java] Iterator iterator = list.iterator(); [/java]

ArrayList の多次元化

わかってしまえば何だ!って感じだけど、ハマった。 [java] ArrayList<ArrayList> daySchedules = new ArrayList<ArrayList>(); [/java] この他に書き方があるのかな?

  2011/04/13

Intentで画面遷移する際、オブジェクトを受け渡したい場合どうするのか? Intent.putExtra() の引数型は「String」「double」「int」「float」「long」「byte」「CharSequence」「char」「Bundle」「Parcelable」「Serializable」「boolean」「short」 となってるので、それ以外のオブジェクトやカスタムクラスを、そのまま受け渡しできないようです。

Serializable を implements する

カスタムオブジェクトを受け渡す場合、事前に Serializable を implements しておく。 [java] import java.io.Serializable; import java.util.Date;

public class Schedule implements Serializable { private static final long serialVersionUID = -7168471472978288786L;

private Date dtstart;
private String title;

public Date getDtstart() {
    return dtstart;
}

public void setDtstart(Date value) {
    dtstart = value;
}

public String getTitle() {
    return title;
}

public void setTitle(String value) {
    title = value;
}

} [/java]

元画面でモデルデータを受け渡す

[java] private void pageDetail(Schedule schedule) { Intent intent = new Intent(CalendarActivity.this, ScheduleDetailActivity.class); intent.putExtra("schedule", schedule); startActivityForResult(intent, 1);
} [/java]

移動先画面でモデルデータを受け取る

[java] public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.schedule_detail);

Intent intent = getIntent();
    Schedule schedule = (Schedule) intent.getSerializableExtra("schedule");
}

[/java]

2011/06/08追記 こちらの方が正しいかも。 [java] public void onActivityResult(int requestCode, int resultCode,Intent data) { if( resultCode == RESULT_OK) { Schedule schedule = (Schedule) data.getSerializableExtra("schedule"); } } [/java]

参考ページ

Android 画面遷移での値の受け渡し

  2011/04/06

Android Market 登録用のアプリを作成するには署名が必要だが、Eclipseを利用するのが便利。

手順

(1) プロジェクトを右クリックして、Android Tools > Export Signed を選択する Android Market

(2) プロジェクトを確認する Android Market

(3) 初回は storekey の作成が必要となるので「Create new keystore」を選択し、keystoreのパスとパスワード入力する。 Android Market 今後、アップデートする時はこの storekey を使う必要があるので、公開したら確実に保存しておく事。

(4) 各項目を入力する。 Android Market

Alias:プロジェクト名など Password:storekeyのパスワード Validity(years):25 (推奨)

「First and Last Name」以下はアプリ登録者によるが、

個人なら「First and Last Name」 会社なら「Organization」

を入力する感じで良いかと。

(5) 最後に .apk の書き出し先を指定する。 Android Market

  2011/04/06

表示・非表示のメソッド setVisibility() は boolean で渡すと思いきや int で渡すという View の仕様。 [java] function void changeTextVisible(boolean isActive) { TextView textView = (TextView) findViewById(R.id.textView); int active = isActive ? View.VISIBLE : View.INVISIBLE; textView.setVisibility(active); } [/java]

  2011/04/06

いやぁ、ハマッたハマった!

Xperia arcでレイアウト表示が拡大される

回転させたり、アプリを開き直すと正常に戻ります。 シミュレータや他の実機ではその症状が起こらない。

はじめは ListView のスクロール処理がおかしいのか?とずっと思い込んでいたが、 簡単なサンプルでも同じ現象が起きました。

Xperia arc上の他のアプリではそのような症状はないので、何かしら設定がある。 でも、わからない。。。 最後はAndroidの会にMLしました。

あっさり解決!

minSdkVersionは必ず設定すること

結論から言うと、SDKのレベルと機種依存でした。 minSdkVersion=4(Android1.6)以上で解決します。 [java] [/java] SDKのレベルが3以前だと、dip指定のオブジェクトが拡大されてしまう。

という事で、minSdkVersionは必ず設定する事ですね。 しかし今回の件で、関係ない API を調べて少しばかり勉強になったり(^^;)

pngファイルの軽量化
Google DriveのIconを再起的に削除
php-markdownでバニラPHPなコードブロック処理
laravel-ffmpeg を使う
2021年版 Ubuntu + certbot + Let's Encrypt でサーバ証明書設定
GihHub のデフォルトでない master ブランチを checkout する
マルチログインで未認証のリダイレクト
Homebrew で Redis をインストール
CSS だけでスムーズスクロール
EC-CUBE4 で Gmail の smtp を利用する
Amazon Linux 2 の amazon-linux-extras とは
UNIQUE カラムのバリデーションで自分自身を除外して更新
フォーム有効期限切れで Page Expired をリダイレクト
ログを日付でローテーションやクリアや削除
Homebrew で PHP8.0 から PHP7.4 にダウングレード
Big sur で zsh 移行と Homebrew アップグレード
Mac に minikube をインストール
途中から .gitignore に追加する
Larevel 6.x から Laravel 8.x にバージョンアップ
Composer で Allowed memory size (メモリ不足)エラー
Blade でカスタムクラスを利用する
git push git pull にブランチ指定せずに実行する
git pull や git push できなくなったとき
Docker のコンテナからホストOS に接続
Mac で ローカル IP アドレス(ipv4)のみを表示する
ホストOS から Docker の MySQLコンテナに接続
caching_sha2_password のエラー
node-config で環境設定ファイルを利用する
rootパスワードを初期化(再設定)する
Git から clone したときのエラー対処
Mac に MySQL をインストール
Mac に PostgreSQL をインストール
Laravel 環境構築 - Mac ネイティブ編
Firebase 入門 - Firebase とは
Firebase 入門 - CLI インストールとデータベースの設定
AWS 無料枠(t2.micro)で容量とメモリエラー
Cloud9 を起動する -初心者編-
gcloud で GCEインスタンスを起動してみる
AWS CLI と jq でインスタンス一覧を整形して表示
React と Laravel7 のプロジェクトを作成する
Homebrewインストール-2020年版
3直線で囲まれた範囲塗りつぶし
PuLP で線形最適化問題を解く
カスタムのペジネーションを作る
node-sass を使って sass をコンパイルする
Log ファサードでSQLログを分離して書き出す
いちから始める Docker - 複数のコンテナを使う - (2020年)
いちから始める Docker - docker-compose を使う - (2020年)
AWS ECR を使ってみる
Laravel7 でマルチ認証