Pages

2012年1月18日水曜日

iOSアプリのデフォルト言語

「iTunes Connect: Editing the default language for your app」

Appleからメールが届きました。

これまで、最初(のアプリ申請時)に選択したデフォルトの言語は変更することはできなかった。
最初に日本語を選んだことを後悔したこともあった。

もうひとつ別のデベロッパ契約を結んで英語で登録しようかと思ったが1社1アカウントということから、それもできなかった。

・・・が、ついにデフォルトの言語を変更することができるようになったようです。
しかもアプリごとに、いつでも変更できるということ。

iTunes Connect 除いてみたら、ちゃんと選択するプルダウンがありました。

2012年1月5日木曜日

OpenOffice をあきらめ LibreOffice へ

あけましておめでとうございます。

今日、OpenOfficeを使ってデータの整理をしようと思ったら途中でフリーズしてしまいました。

シート数は20シートくらいで、各シート内は平均200~300行くらいのデータです。
環境はWindows 7で、OpenOfficeは3.3です。

何度やってもフリーズします。
ほかのもっと小さなファイルで試してみてもやっぱり暫くするとフリーズします。

マウスホイールでスクロールしている最中のフリーズが多かったのですが、そのほかの作業中でもフリーズすることがありました。

3.2のときにMicrosoft Office IMEとの相性どうこうという話があったみたいなので、IMEを切り替えてMicrosoft IMEに変更しましたが結果は変わらず。

結局あんまり時間をかけて、あれこれ試してみるのもしんどいし、スパッとあきらめてLibreOffceの3.4を入れて試してみましたら今のところ問題なく動いてくれています。

よくわからんけど、しばらくはこれで様子を見てみようと思います。

2011年12月17日土曜日

androidでボタンがタッチされたときに画像を変更する

androidアプリでandroid.widget.ButtonのBackgroundプロパティに画像を設定したり、android.widget.ImageButtonのSrcプロパティに画像を設定したりすることはよくあると思います。

iOSでは、これだけでボタンがタッチされたら自動的に画像の明度を落としたようにハイライトしてくれるので、それに甘えているのが常なんですが、androidでも同様かと思いきやandroidでは何もしてくれません。

やはり、ボタンが押されているということを視覚的に表現したいと思いますよね。

まず、私が試したのは、通常の画像(仮にnormal.pngとします)と押された状態の画像(仮にpressed.pngとします)の二種類の画像を用意します。

そして、OnTouchListenerを使用して下のようにイベントリスナーで処理します。

((Button)findViewById(R.id.button2)).setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            ((Button)v).setBackgroundResource(R.drawable.pressed);
        }else if(event.getAction() == MotionEvent.ACTION_CANCEL ||
          event.getAction() == MotionEvent.ACTION_OUTSIDE ||
          event.getAction() == MotionEvent.ACTION_UP){
            ((Button)v).setBackgroundResource(R.drawable.normal);
        }
        return false;
    }
});


注)このときfalseを返さないとOnClickListenerに処理が回ってきません。

ただ、このようにしてもボタンを押したまま指がボタンを外れても画像が戻ってくれませんでした。しかもこのMotionEventの定数は非常に多岐に渡っていて、きちんとやろうと思えばいろいろなケースに対応する必要があり正直面倒そうです。

で、見つけたのがselectorを使うという方法です。drawableの中にselectorというタイプのXMLファイルを作成します。ファイル名が@drawable/...に指定するリソース名になります。

以下のように記述します。


    
    



これで、ちゃんと押したまま指がボタンを外れても元の画像に戻ってくれます。

androidでは、いろんな場面でXMLが活躍するみたいですね。とりあえずはここを極めないといけないかもしれませんね。

2011年11月25日金曜日

iOS5とNSOperation

NSOperationQueueとNSOperationとNSURLConnectionを使って非同期に画像やデータをダウンロードするという処理については、いろいろなところで紹介されていたりして結構メジャーな処理の一つだと思います。

御多分に漏れず私もこの手法の常習者のひとりであります。
この処理を使うアプリもいくつか開発した経験があります。

この処理ではNSOperationのサブクラスを作って各メソッドをオーバーライドするわけですが、cancelの中では、だいたい下のコードのようにプロパティを書き換えるのが普通じゃないでしょうか?

- (void)cancel {
  .....
  [self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"];
  .....
}


ところが、これ、iOS5では[MyOperation isFinished = YES without being started by the queue it is in]なんてメッセージを吐きよる。

つまりは、startメソッドが実行されていないのにisFinishedをYESに設定するとは何事だ!と怒られてしまったわけです。iOS4までではこんなことで怒られることはありませんでした。まぁ、そう言われればそうやなって気もしないではないですが・・・

特に、[queue cancelAllOperations]とかを実行して大量の非同期オペレーションをキャンセルする場合なんかは大量にこのメッセージが出ます。しかも、[An instance 0xxxxxxxxx of class MyOperation is being deallocated while key value observers are still registered with it]とかいうメッセージも吐きだされて、これが直接的に関係しているかどうかは不明ですがアプリが落ちてしまうこともしばしば。

ではメッセージを回避しようということで、cancelメソッドの中を以下のように書きえてみました。



はい。メッセージは吐きだされなくなりましたが、今度はNSOperationがNSOperationQueueから削除されずに残り続ける結果に。

う~ん。どうしたものか。正しいお作法が見つかるまでは、とりあえず自作の疑似キューを作成して非同期通信キューの処理を実現することにしました。

松竹芸能 不公平ワリカン リリース

「松竹芸能 不公平ワリカン」というiPhoneアプリをリリースしました。
11月25日からAppStoreで購入可能です。

http://itunes.apple.com/jp/app/id480923725?mt=8

ゲーム感覚の割り勘アプリです。
ただの割り勘はつまらないんで、ちょっとスリリングに不公平な割り勘が楽しめるアプリ。

これ、僕の中ではかなり前から案があってアプリ化したかったんですが、どうやったらより楽しくなるかなっていうのが悩みの種でした。

堅いのもいややし、ギャグにするとしてもデザインとかがキャッチーな方がいいし・・・とかいろいろ考えて長い時間が経ってしまいました。

そんな中、ひょんなことから松竹芸能さんと一緒にできるチャンスが訪れまして、とてもラッキーでした。

ということで、よかったらどうぞ。

2011年11月16日水曜日

iOS5のステータスバーどうなってんの?

以前に作ったiPhoneアプリをiOS5で実行してみたら「あれっ???」って思う事がありました。

半透明に設定したステータスバーの後ろの描画がiOS4のときと見え方が違うのです。1ピクセル下にずれてるのです。

どういうことなんだってことで簡単な実験をしてみました。

まずは、ステータスバーをUIStatusBarStyleBlackTranslucentで黒の半透明に設定してビューをウィンドウいっぱい(320x480)に表示させてビューの描画ルーチンを以下のように記述します。

- (void)drawRect:(CGRect)rect {
  CGContextRef context = UIGraphicsGetCurrentContext();

  CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 0.5);
  CGContextFillRect(context, CGRectMake( 80.0,  0.0, 16.0, 20.0));
  CGContextFillRect(context, CGRectMake(100.0,  0.0, 16.0, 19.0));
  CGContextFillRect(context, CGRectMake(120.0, 20.0, 16.0, 30.0));
}


まずは、iPhone 4.3 Simulatorで実行します。
結果は以下の通り。予想通りです。


で、次にiPhone 5.0 Simulatorで実行してみます。
結果は以下の通り。


おいおい、明らかに隙間が空いてるやないか!

で色々、書き加えたりしているうちに再描画(setNeedDisplay)を実行したらなぜか普通の状態に変わるということが分かりました。他にもきっかけはあるかもしれませんが。

とりあえず、ボタンを付けてボタンのセレクタで再描画を実行するようにしてみました。

そのときの動きがこれ。※ちょっと分かりにくくてすいません。



動いてる〜。
再描画後は正常というか想定していた状態になりました。


2011年11月13日日曜日

CoreAnimation CATransaction

CoreAnimationで、CATransactionを使う方法はシンプルで手軽なんで結構楽しめますよね。

もう識者の方にとっては当たり前で知ってることだとは思いますが、自分なりに簡単な実験を行ってみたので、ここに書き留めておきます。

とりあえず、100x100の青背景のCALayerを作ってアニメーションさせます。
アニメーションの開始はviewDidAppearとします。

まずは、5秒かけてゆっくり左上から右下にレイヤーを移動させながら、最初の1秒間でレイヤーの透明度を変更するという二つのアニメーションの組み合わせのパターン。
これは、CATransactionをネストすることで可能です。

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];

  [CATransaction begin];
  [CATransaction setAnimationDuration:5.0];
  animLayer.frame = CGRectMake(200.0, 340.0, 100.0, 100.0);
  [CATransaction begin];
  [CATransaction setAnimationDuration:1.0];
  animLayer.opacity = 0.3;
  [CATransaction commit];
  [CATransaction commit];
}


これをiPhoneシミュレータで実行させたらこうなります。


では、この透明度を変更するのがアニメーションの開始から3秒後に始めたい。こんな場合はどうするのってことで、以下のようなコードを書いてみました。タイマーを使用します。

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];

  [CATransaction begin];
  [CATransaction setAnimationDuration:5.0];
  animLayer.frame = CGRectMake(200.0, 340.0, 100.0, 100.0);
  [CATransaction commit];
  //
  [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(onTimer:) userInfo:nil repeats:NO];
}

- (void)onTimer:(NSTimer*)timer {
  [CATransaction begin];
  [CATransaction setAnimationDuration:1.0];
  animLayer.opacity = 0.3;
  [CATransaction commit];
}




CATransactionはあとから実行しても追加して複数のアニメーションを組み合わせて実行くれるみたいですね。
では、こんなことしてみたらどうでしょうか?

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];

  [CATransaction begin];
  [CATransaction setAnimationDuration:5.0];
  animLayer.frame = CGRectMake(200.0, 340.0, 100.0, 100.0);
  [CATransaction commit];
  //
  [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(onTimer:) userInfo:nil repeats:NO];
}

- (void)onTimer:(NSTimer*)timer {
  [CATransaction begin];
  [CATransaction setAnimationDuration:1.0];
  animLayer.frame = CGRectMake(20.0, 20.0, 100.0, 100.0);
  [CATransaction commit];
}



まぁ当然そうなりますよね。
CABasicAnimationでいうところのanimationWithKeyPathのkeyPathが同じものを重ねて追加すると上書きというか前のものが取り消されて後から追加したアニメーションが実行されます。

で、途中でアニメーションを中止させるには以下のようにすれば可能です。

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];

  [CATransaction begin];
  [CATransaction setAnimationDuration:5.0];
  animLayer.frame = CGRectMake(200.0, 340.0, 100.0, 100.0);
  [CATransaction commit];
  //
  [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(onTimer:) userInfo:nil repeats:NO];
}

- (void)onTimer:(NSTimer*)timer {
  [animLayer removeAllAnimations];
}