1×1のバッテリーウィジェットのBatteryCrystalをリリースしました。
バッテリー残量によってクリスタルの色が変わるようになってます。
中央にはバッテリー残量が半透明の文字で表示されるので、
何気にちょっとおしゃれ感を出してます。
まぁ素材自体は本を見ながら作ったまんまなんですが…。
(グラデーションとかいじっただけ…)

例によってリリースしたのでサポートページ作っとりますので、
そちらをご確認ください。
サイドバーのプロフィールのところにリンク付けてます(うわ、超手抜き…
2010年 9月 4日
1×1のバッテリーウィジェットのBatteryCrystalをリリースしました。
バッテリー残量によってクリスタルの色が変わるようになってます。
中央にはバッテリー残量が半透明の文字で表示されるので、
何気にちょっとおしゃれ感を出してます。
まぁ素材自体は本を見ながら作ったまんまなんですが…。
(グラデーションとかいじっただけ…)

例によってリリースしたのでサポートページ作っとりますので、
そちらをご確認ください。
サイドバーのプロフィールのところにリンク付けてます(うわ、超手抜き…
2010年 8月 26日
AndroidSDK開発のレシピのレシピ61「音声ファイルを再生する」を読みながら、Androidでボタンが押されたタイミングで音を出そうとプログラムしたところ、出ない…。SoundPoolクラスを使ってoggファイルで音を出そうとしました。
// HogeというActivity内
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
int[] sounds = new int[5];
SoundPool soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
sounds[0] = soundPool.load(Hoge.this, R.raw.switch, 1);
soundPool.play(sounds[0], 1.0f, 1.0f, 0, 0. 1.0f);
soundPool.release();
}
});
DDMSでログを見たところ、WARN sample 1 not READYというメッセージが。準備できてへんと。sample 1 not READYでググったら、英語のサイトで「初期化するのに時間がかかるからちょっと時間を置け」って書かれてた。どうやって…?
ボタンを押したタイミングで鳴ればいいわけだから、onResumeのタイミングでロードしておき、onPauseのタイミングでリリースするようにしておけばいいのかなと思ってやってみたらビンゴでした。
// HogeというActivity内
private SoundPool mSoundPool;
private int[] mSounds = new int[5];
protected void onCreate(Bundle savedInstanceState) {
// ... ゴニョゴニョと処理をしとく
btn.setOnClickListener(new OnClickListener(){
public void onClick(View v){
mSoundPool.play(mSounds[0], 1.0f, 1.0f, 0, 0. 1.0f);
}
});
}
protected void onResume(){
// 音をロードしておく
mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
mSounds[0] = mSoundPool.load(this, R.raw.switch, 1);
}
protected void onPause(){
// 音をリリース
mSoundPool.release();
}
以上、備忘録でしたー!
2010年 8月 25日
コメントにて、Androidに元々入っているギャラリーのような動きをさせるその後はどうなったんだ!?という質問を受けましたので、公開してしまおうと思います。ただ、当然ながらこれは私の独自のやり方なので、はっきりいって正しいかどうかはわかりません。
あと、画像の拡大・縮小にはAnimationを使っております。ドラッグ移動はできますが、ビヨーンといった跳ね返りとかは実装していません(そこまで精神がもたなかった)。やろうと思えばできるんでしょうけどねぇ〜。
イベントはダブルタップとかドラッグとか使うので、OnGestureListenerとかOnDoubleTapListenerは必須。implementsしておいてください。
で、画像の拡大・縮小はそんなに難しくないので、省略するとして(オィ)、問題はドラッグ移動なわけです。
画像のドラッグについては、下のメソッドで動くはず。なんで動くのか?を説明するのは結構難儀ですが。
ちなみに、拡大率は2倍固定です(面積は4倍)。
// private Rect mRect
// private Matrix mMatrix = new Matrix();
// private float[] mValues = new float[9];
private void imageMove(ImageView iv, MotionEvent e) {
if (e.getHistorySize() > 0) {
int x = (int) e.getHistoricalX(0) - (int) e.getX();
int y = (int) e.getHistoricalY(0) - (int) e.getY();
iv.scrollBy(x, y); // ①
int new_x = iv.getScrollX();
int new_y = iv.getScrollY();
mRect = iv.getDrawable().getBounds();
mMatrix = iv.getImageMatrix();
mMatrix.getValues(mValues);
// ②
// 画面上の画像の横サイズ
int iw = (int) ((int) mRect.width() * mValues[Matrix.MSCALE_X]);
// 画面上の画像の縦サイズ
int ih = (int) ((int) mRect.height() * mValues[Matrix.MSCALE_Y]);
// 画像の横サイズの半分
int iw_harf = iw / 2;
// 画像の縦サイズの半分
int ih_harf = ih / 2;
// 縦方向の黒くなっているところの高さ
int black_out_w = (iv.getWidth() / 4) - iw_harf;
// 縦方向の黒くなっているところの高さ
int black_out_h = (iv.getHeight() / 4) - ih_harf;
Log.d("imageMove", "new_x=" + Integer.toString(new_x) + ", new_y="
+ Integer.toString(new_y));
Log.d("imageMove", "_x=" + Integer.toString(iw) + ", _y="
+ Integer.toString(ih));
Log.d("imageMove", "black_out_w=" + Integer.toString(black_out_w)
+ ", black_out_h=" + Integer.toString(black_out_h));
// 拡大画像がはみ出ないようにする処理
if (Math.abs(new_x) > black_out_w || Math.abs(new_y) > black_out_h) {
// new_x, new_yが0の場合を考慮する必要あり
if (new_x == 0 && new_y == 0) {
// 何もしない ③
} else if (new_x == 0) {
iv.scrollTo(0, new_y
/ Math.abs(new_y)
* (int) Math.min(Math.abs(new_y), Math
.abs(black_out_h))); // ④
} else if (new_y == 0) {
iv.scrollTo(new_x
/ Math.abs(new_x)
* (int) Math.min(Math.abs(new_x), Math
.abs(black_out_w)), 0); // ⑤
} else {
iv.scrollTo(new_x
/ Math.abs(new_x)
* (int) Math.min(Math.abs(new_x), Math
.abs(black_out_w)), new_y
/ Math.abs(new_y)
* (int) Math.min(Math.abs(new_y), Math
.abs(black_out_h))); // ⑥
}
}
}
}
では説明しまーす。
まず、①で、普通のドラッグ移動を行います。
ヒストリーが取れるので、前の場所から移動した分だけスクロールするよって処理です。
②で、画像の大きさや画面からはみ出る範囲や背景が黒くなっている部分の大きさを計算・取得します。正直ここが一番面倒というか、わかると簡単なんですが、辿り着くのに数日かかりました。アホです。図にして考えるとやりやすい(手書きでガシガシ書いたので、残ってない…)。
Matrixから画像の拡大率を取ります。これは何故かというと、画面よりもでかい画像を読んだら縮小して表示されるんですが、Rect.width()に本来の画像の横サイズが入っているので、それに拡大率をかけることによって画面内における画像の横幅を取得します。縦幅も同様に。
で、画像が画面とまったく同じ大きさでもない限り、黒抜きにされるから、その黒抜きの幅を取得します。これは表現として合ってないかもしれませんが。
③です。これ以降が、画像どこかしらが画面の端っこにきている場合の処理です。普通の場合はscrollByをしていましたが、それ以外の場合はscrollToで上書きする感じになります。
iv.getScrollX()は、親要素に対してスクロールした量だったかな…。割り算をやるので、0の場合は処理しないように制御しないと、例外が発生してアプリが落ちますので、ご注意を。それらが、③、④、⑤。基本は⑥の処理。
という感じです。すみません、眠い頭で書いてるので、説明がグダグダかもしれませんが、メソッド自体は合ってると思います。(但しアニメーションで画像を2倍にしたときに限る)
以上です。
2010年 8月 23日
Androidアプリの第二弾として、組み計算というアプリをリリースしました。
色々な組み合わせで計算をしたい場合などに使えるようなアプリです。まだちょっと完成度は低いかもしれませんが…(だからバージョン0.1.0です)。
早速、紹介ページを作りました。
サイドバーのアプリのところか、以下のリンクからどうぞ!!
2010年 8月 19日
@yanzmさんのブログで紹介されているまんまなんですが、備忘録に書かせてもらいます。
まずは何故、俺がこれを実装する必要があったかの経緯を書きます。
いろいろあって、GridViewで画像の一覧を表示する必要があるのですが、その前のアクティビティでは検索フォームがあり、その検索用アクティビティでソフトウェアキーボードを開いた状態で検索ボタンを押して画像一覧アクティビティに来たら、Out of Memoryでアプリが落ちました。ええ、HT-03Aでです。Desireだと落ちなかったのでわからなかった…。
HT-03Aでもずっとテストしていたのですが、画像一覧アクティビティで画像がたくさん出ても落ちないかどうかのテストはやっていたのですが、面倒だったので検索条件なしでずっと実験していたため、ソフトウェアキーボードを開いた状態で画像GridViewにきたら落ちるなんて夢にも思ってませんでした。
なので、検索ボタンを押したらソフトウェアキーボードを消すようにして実験してみたところ、HT-03Aでもアプリが落ちなくなりました。恐るべし、ソフトウェアキーボード!!
参考にしたyanzmさんのブログ記事は以下のURL。
http://y-anz-m.blogspot.com/2009/12/android.html
// 検索ボタンを押したときのイベント
this.btnSearch.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// キーボードを消す
InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
// 次のアクティビティに渡すIntentの呼び出しなど
}
}
2010年 8月 15日
土曜日の朝日新聞の一面に住宅ローンについての記事が出ていた。読んでいると、なんだか悲しくなってくるなぁ。それなりの幸せを手に入れるために住宅ローンを組んで家を購入したわけだけれど、会社が倒産して再就職ところ給料が減ってローンが払えなくなり、担保にしていた家が競売にかけられて売られてしまう。また、当然ながら安く売られてしまうので、ローンを完済できるわけもなく、家を失い、ただただローンが数百万円残ったという…。働いてもローンに搾取される人生だけが残るという感じ。
以前は、こういう記事を見ていたら、「本人の勉強不足でこういう事態に陥ったわけだから、自己責任だろ。相手も商売でやってるんだから、ちゃんと計画立てろよ」とか思っていたわけだが、今はちょっと違う。違うといっても、半分はそう思ってるけど。そもそもローンを組んで家を買うことに対しては俺は否定的だし。家は財産だなんて思ってないし。まぁこの辺りの話は「金持ち父さん貧乏父さん」とか読んだらわかる。
つーか、サブプライムローンみたいだよなぁ〜。低所得者に高利で融資して家を買わせる。で、家の価格が上昇している間はそれでいいけれど、バブルが弾けたら利子さえ払うのが苦しくなって家を売りに出されて本人は段ボールハウスに住むみたいな…。全然幸せじゃない。売る側も、買う側も。資本主義の悪い面だけが顔を出しているように思える。
幸せのモノサシが、他人との比較しかできない物ならば、そんなモノサシはへし折ってしまえ!!
いい加減、世間が作り出した理想なんかには影響を受けない生き方を模索するべきですな。人様にすごく迷惑にならない限りは世間体なんてどうでもよく、ほどほどに暮らせていられれば幸せなんじゃないでしょうかね〜。今日食べられるご飯と飲める水があるだけで、相当幸せなこと。相対的貧困を意識し過ぎて、心まで貧困になってはならないと思います。
※相対的貧困・・・世間が作り出した、中流の基準以下の生活による劣等感。
と、ここまで書いて、投稿を終わろうとしたのだけど、よく見たら、なぜ「自己責任」でカタを付けないか?を書くのを忘れそうになっていた。反貧困ネットワークの湯浅 誠さんが出ている番組とかを見ている間に、これは「自己責任」という一言で片付けられる問題ではないなぁと思ったからです。個々が知識武装をしていないと安心して暮らせない世の中ってのも、相当歪んでると思うし…。そもそもそれだと生きるのがしんどいんじゃないかなって…。
何事も自己責任だから、絶対的貧困に陥るのも自己責任っていうのは暴論だなと。
※絶対的貧困・・・今日食べるご飯、水にも困るほどの状態。
2010年 8月 12日
Twitterのほうで先に報告しましたが、私個人の開発アプリとしての第一弾として、音声エディタをAndroid Marketにリリースしました。


どういうアプリかといいますと、Googleの音声検索アプリを使って、自分でしゃべった言葉を文字列に変換します。
ただ、音声検索は文脈を理解できないため、句読点や、「〜」「…」「!」「?」「・」という日本人がよく使う記号をソフトウェアキーボードなしで入力できるようにしました(これだけのために毎回ソフトウェアキーボード開くのが鬱陶しいため)。
入力した文字列は、コピーボタンを押してクリップボードにコピーするのはもちろんできますが、連携ボタンを押すことでAndroidならではの機能「他のアプリにデータを渡す」ということができます。
これはどういうことかというと、自分でしゃべった内容をすぐにメールにしたり、ツイッタークライアントに渡して本当に呟けるということです。WordPressとか入れてるとしゃべった内容でブログの更新もできます!(但し、タイトルは手入力で)
対応機種というか、対応OSはバージョン1.5以上にしていますが、まぁ日本のAndroidOSはほとんどが1.6以上なので、実質ほとんど大丈夫だと思います。
■検証端末
・Softbank X06HT(Desire) 私のケータイ
・Docomo HT-03A 会社の先輩のケータイ
HT-03Aで動作したので、他でも問題ないはず。
問題がありましたら、フィードバックかTwitter上で報告お願いします。
twitter id: patorash
もしAndroidケータイを使っていましたら、Androidのブラウザで以下のリンクをクリックするか、Android Marketで「音声エディタ」で検索して、インストールしてみてください!ヨロシクお願いします。
Androidアプリ 音声エディタ
(PCからクリックしたら、Not Foundに移動するのでご注意を)
2010年 8月 11日
個人でAndroidアプリを思いつきで作ったのですが(まだリリースしてない)、そのときに他のアプリを呼び出したいなぁと思ったのだけれど、やり方がわからなかったんで調べました。自分で作ったアクティビティだけに限りませんが、特定のアクティビティを呼び出すのを明示的Intent呼び出しというのに対して、とりあえずIntentを作ってデータを放って、ユーザ側にアプリを選択させるのを暗黙的Intent呼び出しというらしいですね。
参考にさせてもらったのは以下のサイトです。
Intent(インテント)連携をまとめてみる – コードを貼り付けながら。
今回はEditTextに入力された内容を、メーラーやtwitterクライアントに対して渡すというのを実装してみました。
// ActivityのonCreate内
// 他のインテントを呼び出す
btnCollaboration.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
String data = editText.getText().toString();
if (data.length() > 0) {
try {
// メーラーやtwitterクライアントなどを呼び出す
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, data);
startActivity(Intent.createChooser(intent, getString(R.string.txt_please_select)));
} catch (ActivityNotFoundException e) {
e.printStackTrace();
// 呼び出せるActivityが存在しない
Toast.makeText(VoiceEditor.this, R.string.txt_no_collaboration_found, Toast.LENGTH_SHORT).show();
}
} else {
// EditTextにデータがないのでToast呼び出し
Toast.makeText(VoiceEditor.this, R.string.txt_no_text, Toast.LENGTH_SHORT).show();
}
}
});
全部を自分で実装しなくても、入り口だけ作ってあとは他のアプリにデータを渡せるってのは、便利ですねぇ。
2010年 8月 7日
MapActivityを継承したアクティビティで、ダブルタップしても地図がズームインしないので、これはGoogleMapの仕様に合わせたいなぁと試行錯誤した結果を記します。正直、しんどかった。
まぁ、似たようなことを考えている人は世の中にもおられるもので、そこを参考にさせてもらいました。
まぁ上記のサイトにも書かれているのですが、OnGestureListenerをimplementsしただけでは、MapActivityはタップイベントを拾ってくれません。理由はMapViewが先に拾っちゃうからです。原因がわかったとしても、じゃあどうすればいいか。それがなかなかわからなかったんですが、上記のサイトでヒントを書いてくれてるので、それを参考にします(上記のサイトのは俺がいうのも何だけど、完璧ではなかった…)
下のソースは実際に使ってるものの、処理をかなりパッサリと落として抽出したものです。
public class Place extends MapActivity implements LocationListener,
OnGestureListener,
OnDoubleTapListener{
private boolean mZoom = false;
private boolean mDoubleTap = false;
private boolean mSingleTap = true;
private MapView mMapView;
private MapController mMapController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.place);
mGDetector = new GestureDetector(this, this);
mMapView = (MapView)findViewById(R.id.mapview);
mMapView.setBuiltInZoomControls(true);
ZoomButtonsController zbc = mMapView.getZoomButtonsController();
zbc.setOnZoomListener(new OnZoomListener() {
@Override
public void onZoom(boolean zoomIn) {
mZoom = true;
if(zoomIn){
mMapController.zoomIn();
} else {
mMapController.zoomOut();
}
}
@Override
public void onVisibilityChanged(boolean visible) {
}
});
// ...略
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
super.dispatchTouchEvent(ev);
return onTouchEvent(ev);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
mDoubleTap = true;
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent event) {
if (mDoubleTap) {
mDoubleTap = false;
GeoPoint gp = getGeoPointByPoint((int)event.getX(), (int)event.getY());
GeoPoint cgp = mMapView.getMapCenter();
GeoPoint point = new GeoPoint(
(gp.getLatitudeE6() + cgp.getLatitudeE6()) / 2,
(gp.getLongitudeE6() + cgp.getLongitudeE6()) / 2);
if (mMapController.zoomIn()) {
mMapController.setCenter(point);
}
}
return false;
}
@Override
public boolean onDown(MotionEvent event) {
mSingleTap = false;
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
mSingleTap = true;
if (mZoom) {
// zoomIn, zoomOutしていたら、処理をしない
mZoom = false;
} else {
GeoPoint gp = getGeoPointByPoint((int)event.getX(), (int)event.getY());
mMapController.animateTo(gp);
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGDetector.onTouchEvent(event)) {
return true;
}
return super.onTouchEvent(event);
}
private GeoPoint getGeoPointByPoint(int x, int y) {
Projection projection = mMapView.getProjection();
return projection.fromPixels(x, y);
}
}
まず、イベントを全部横取りするために、dispatchTouchEventメソッドを設定します。最初にMapActivityが持っているイベント類を全て実行させるために、super.dispatchTouchEventを実行します。その後、実行したいthis.onTouchEventにイベントを渡します。
this.onTouchEventの中で、GestureDetector.onTouchEventをやっておきます。
重要になるのが、onSingleTapConfirmedメソッド。これは簡単にいうと、シングルタップイベントに該当します。シングルタップで実行したい処理をここに書いてしまいます。これでシングルタップイベントは完成っぽく見えるけど、実は違います。あとで書きますが、罠が潜んでます。
次に、onDoubleTapEvent。これはダブルタップイベントという名前だけあって、そういうイベントなんですが、何故かonDoubleTapメソッドの後に数回コールされてしまうので、onDoubleTap内で現在ダブルタップ中というフラグを立てて、onDoubleTapEventでフラグが経っていたら処理するというふうにします。これで、ダブルタップイベントは完成。
これで、GoogleMapをダブルタップしたら、地図は拡大。シングルタップしたところが画面中央に来てハッピーかと思いきや、なんと、ZoomControlをクリックしたら、シングルタップイベントが走ってしまい、ズームコントロールを押した場所が画面中央に来てしまいます。これはどげんかせんといけませんな。
で、onCreateの中でやっているんですが、ZoomButtonsControllerのインスタンスを生成して、ズームボタンを押したときのイベントを自分で定義します。setOnZoomListenerというやつですね。ここで、onZoomイベントに来たら、現在ズーム処理中のフラグを立てます。あとは拡大・縮小の処理を実行します。
onSingleTapConfirmedメソッドで、ズーム中のフラグが立っていたら、処理をしないようにします。そうすれば、シングルタップOK, ダブルタップOK, ズームコントロールOKになります。ふぅ〜、やれやれだぜ。
コメント
コメントはありません