2012年11月28日水曜日

ViewFlipperでページめくり ~おまけ編

ここからはおまけ.

前回の続きでフリックでページをめくる処理を実装する.
要するにフリックイベントを取りに行くわけでもはやViewFlipperほとんど関係ない気がする('A`)

OnGestureListenerをもちいたフリックイベントの取得

ついにタイトルすらViewFlipperから遠のいたけど気にしない.
実装するのはActivity. ここに

implements OnGestureListener

してやる. 当然 eclipse「メソッドのオーバーライド足りてねぇぞゴルァ(゚Д゚#)」と怒られるので言われるままに作成.
ただし今回使うメソッドは2つのみ.

① onFling
② dispatchTouchEvent

特に②が忘れられがちなので注意

① onFling

実際に受け取ったフリックイベントから処理を行なうクラス. 

@Override
public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) {
    float dx = Math.abs(e1.getX() - e2.getX());
    float dy = Math.abs(e1.getY() - e2.getY());
    if (dx > dy) {
      if (velocityX > 0) {
        flipper.setInAnimation(slideInFromLeft);
        flipper.setOutAnimation(slideOutToRight);
        flipper.showPrevious();
      } else {
        flipper.setInAnimation(slideInFromRight);
        flipper.setOutAnimation(slideOutToLeft);
        flipper.showNext();
      }
      return true;
    }
    return false;
}

たまにはsyntaxhighlighterの色を変えてみたかった(言い訳)ので参考サイトをほぼコピペを更にコピペというだめっぷりorz
3行目, 4行目でフリックのX方向, Y方向の移動距離をそれぞれ取得,
5行目で比較してX方向のほうが大きい=横にフリックする気でフリックした 時のみ処理を行なう.
6行目でフリックのベクトルが右方向か左方向かを判定, 右なら1ページ戻る, 左なら1ページ進む, を処理させる. 処理の内容は前回参照.
それだけ. これでイベントが飛んでくれば処理してくれる.

②dispatchTouchEvent

一度ここを設定し忘れて「あっれーうごかないぞー(゜д゜;三;゜д゜)」とか言ってたことがあるのでorz
まずonCreateあたりで

GestureDetector gestureDetector = new GestureDetector(this, this);

を取得.
そして問題のdispatchTouchEvent
@Override
public boolean dispatchTouchEvent(final MotionEvent event) {
  return gestureDetector.onTouchEvent(event) || super.dispatchTouchEvent(event);
}

eclipseの自動生成に出てこない引っ掛けっぷり. ひどすぎる('A`)
コイツを作っておかないとそもそもイベントを取ってくれませんorz


これらを設定してやると, おめでとう!ボタンで動いていた画面がフリックで移動するようになったぞ!
となる.

onFlingの3行目, 4行目でとったように, e1.getX()でとった座標で条件分岐してやれば, 特定の範囲でフリックしたときのみイベントを取るなんてのもできそう. やってないけど(・ω・`)





長かった…('A`)

ViewFlipperでページめくり ~動作編


前回からの続き. ようやくページめくりのお話.

B. コード上で動きを指定

とりあえず

ViewFlipper flipper = (ViewFlipper) findViewById(R.id.flipper)

で ViewFlipperを取得.
ページを送る/戻す処理は

flipper.showNext()/flipper.showPrevious()

これだけ.
これをボタンのクリックイベントだったり画面のフリックイベントだったりに呼ぶようにしてやれば, それだけで次の/前の子ビューを表示してくれる.便利!

ただこれだけだと一瞬でページが切り替わる非常に味気ないページめくりに…
なので折角だしアニメーションを仕込んでみる.

手順は
① アニメーションの情報を仕込んだxmlを作成
② ①を基にflipperにアニメーションをセット
の2本立てでお送りします

①xmlを作成

まずはres/animを作成. 基本自動生成はされていないので自作のはず.
ここにAndroid XML File を作成します. RootElementは「translate」.
内容は,

<?xml version="1.0" encoding="utf-8"?>
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="-100%p"
    android:toXDelta="0%p"
    android:fromYDelta="0%p"
    android:toYDelta="0%p">
</translate>

ためしに左からページが画面に入ってくるアニメーション.

android:durationがアニメーションに書ける時間(ミリ秒)
XDelta, YDeltaはそれぞれViewの左上の座標の位置を指定. 0%pで今写っている画面の左上を指す.
fromがアニメーション開始時の位置, toがアニメーション終了時の位置を指す.
のでこのアニメーションは,
画面外ちょうど画面1枚分左から, 500ミリ秒かけて画面ぴったりに収まるように入ってくる
アニメーションとなる.
ちょっと指定を変えれば出ていく, 逆方向の動きはもちろん, 斜めからスライドイン/アウトだって指定できちゃう(゚∀゚)ラクチン!

これを,
1. 左から入ってくる
2. 右へ出て行く
3. 左へ出て行く
4. 右から入ってくる
の4タイプ分用意します.

②flipperにアニメーションをセット

xmlを用意できたらいざセット

Animation slideInFromLeft = AnimationUtils.loadAnimation(this, R.anim.slide_in_from_left);
Animation slideOutToRight = AnimationUtils.loadAnimation(this, R.anim.slide_out_to_right);
flipper.setInAnimation(slideInFromLeft);
flipper.setOutAnimation(slideOutToRight);

slide_in_from_leftがちょうど①に挙げたxml. 同様にAnimation を作成し, InとOutそれぞれflipperにセットしてやる.
新しいページの入り方と古いページの出方…のはず(・ω・`)
これでOK.
ただしIn, Outそれぞれアニメーションは1個ずつしか登録できないため, 上記のコード全部で右にページを送る処理ひとつ.
左にページを送る逆向きの処理を同じ flipperにセットしたい場合, 処理を呼び出すごとにセットしてやらないと, 最後にセットしたアニメーションのみ実行することになります.
なので1ページ戻るアニメーションを実現するなら,

 flipper.setInAnimation(slideInFromLeft);
 flipper.setOutAnimation(slideOutToRight);
 flipper.showPrevious();

これ全部を「戻る」ボタンあたりのonClickで呼んでやる必要がある.逆もまた然り.


これで一応アニメーションしながらページめくりはできる. できるけど…なんか違う.
やっぱりフリックでページをめくりたい!


なのでさらに続けてみます.







あともうちょっとだけ続くんじゃ('A`)

ViewFlipperでページめくり ~ページ作成編

ホーム画面やらiPhoneやらでおなじみ横フリックでページめくり.
これを利用して, 数ページに分割したランキングを作りたい! と調べてみたら, ViewFlipperなんて便利そうなViewを見つけたヽ(・ω・)/.

ViewFlipperで簡単ページめくり


必要なものは
A. <ViewFlipper>タグを用意
B. コード上で動きを指定

まずはxml

A. <ViewFlipper>タグを用意

使いたいActivityのレイアウトに

<ViewFlipper
       android:id="@+id/flipper"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" >
</ViewFlipper>

これだけ. 実に簡単. ちなみにこの外にボタンやらなにやら置いてもOK. Layout内で<ViewFlipper>タグが陣取ったエリアだけでページめくりしてくれます.

ただしこのままだとめくる「ページ」が無いので, 中に子ビューを入れる.
入れる方法は2通り.

①. このままxmlに突っ込むぜ!
② いやコード上で動的に作りたいんで

①はまた楽. <ListView>なんかと同じようにタグの間に宣言するだけ.
例えば…

<ViewFlipper
       android:id="@+id/flipper"
       android:layout_width="match_parent"
       android:layout_height="wrap_content" >
       <include android:id="@+id/flipper_child" layout="@layout/flipper_child"/>
</ViewFlipper>

<include>を使うと見やすくまとまってよろしいかと.flipper_child.xmlはまた別にLayoutを作って用意しておけばOK. ただ<include>は2個以上入れないとページめくりになりません. まぁ当たり前だけど('A`)
ページ数が決まっているならばこっちがオススメ.

②はちょっとめんどい. 追加自体は

ViewFlipper flipper = (ViewFlipper) findViewById(R.id.flipper);
flipper.addView(childLayout)

問題はこのchildLayout.すでにLayout自体ができているならひたすらViewを作成→addViewで良いのだが, それなら<include>使ったほうが誤爆は少ない.
また今回は順位表のように決まったLayoutを使いまわして作りたかったうえに, 何ページになるかが決まっていない始末.仕方が無いので子ビューのLayout.xmlを一枚テンプレート的に用意して動的に内容を作って addしていく.


View childLayout = this.getLayoutInflater().inflate(FLIPPER_CHILD_LAYOUT_ID, null);
ListView list = (ListView) childLayout.findViewById(R.id.list);
list.setAdapter(listAdapter);
list.setScrollingCacheEnabled(false);
list.setOnItemClickListener(itemListener);


完璧今回使ったもののコピペ. 手抜きではありません. ええ決して.
1行目で子ビューを新規生成. FLIPPER_CHILD_LAYOUT_IDは子ビューのLayout.xmlのid. 第二引数は今回は特に親のViewGroupをとらないのでnull…で良いのかな(・ω・`)
2行目は子ビューのLayout.xml内に自分で設置したListViewを取得. childLayoutからfindViewByIdしている点には注意.
3行目はそのListに値をぶち込む処理. Adapterに関しては今回はノータッチ. ただ何ページも作る際はAdapterを毎回新しく作るなどちゃんとしておかないと同じ内容のデータが延々と並ぶ苦行のFlipperが完成するので注意.
4行目は完全にListViewの設定. これをしておくとListViewスクロール時, 背景の色が変わるアレを無くすことができます. 背景色を指定しているときなんかに合わせてどうぞ. Flipper関係ねー.
5行目もListの OnItemClickListener のセット. ここで毎回ちゃんとしておくとどのページのListViewもイベントが取れるようになります. ただListenerの中でgetitemする際は,

ListView list = (ListView) parent;
Object item = (Object) list.getItemAtPosition(position);


しておかないとうまく取れないかも…
ともあれこれでFlipperにページを収められたはず.

…長くなっちゃったのでページを動かす処理は次回


2012年11月13日火曜日

selectorを用いた表現

androidに標準に入っているButton
押したら青く?反応するこの反応の色なんかを自分で設定できるらしいのでやってみた.


selectorの利用


例えばこんなボタン
いつものボタンを用いず, 背景色で色付けしたものだが, 当然このままでは押しても視覚的に変化は無し.
希望としては, ボタンをタップしたら,

例えばこんな風
に色が変わって反応して欲しいもの. だからといって押されるたびに

setBackgroundColor(int Color)

とかいってセットしては指が離れたらまたセットしなおすとかとてもじゃないけどめんどくさい('A`)

そこで登場 selector 

1. selector.xmlの用意

前回のグラデーションのお話でも用いた, res/drawableディレクトリを使用.やっぱり色は先に作っておくのが吉. またボタンに表示するテキストは drawableではいじれないので, res/colorディレクトリへ内容がほぼ同じものを, テキスト用 selector.xmlとして作って使いましょう.

わかりやすい名前で.xmlを作成.この時, ボタンを押されたとき, 押されていないとき両方の色の指定をこの.xmlでやるので, わざわざそれぞれ.xmlを作ったりしないように.

xmlを作成する際, selector を先に Root Element: から選んでおくと楽…かな(・ω・`)
どうせ中で宣言できるけど.


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true"  android:drawable="@color/押されたときの色"/>
    <item android:state_pressed="false"  android:drawable="@color/普段の色"/>
</selector>

よくある話で <selector> がデフォルトの <animation-list> になっているまま作成→動かねえぞこれ
(゜д゜;三;゜д゜)
なんてこともあるので注意. …ないか('A`)
<selector>の中に2つの<item>を入れ子にして宣言. <item>にはそれぞれ"状態"がtrueのとき, falseのとき, それぞれ使う色を指定できる.
また"状態"にあたるのが

android:state_pressed


これが"ボタンが押されている状態"を表す. なのでこの場合はボタンが押されていれば上, 指が離れたら下の<item>を参照するぞ, というselectorになる.

ちなみにこの"状態", ラジオボタンに用いたいときは,

android:state_checked

を用いる必要がある. でないと押した瞬間だけ色が変わるラジオボタンの出来上がりである.orz
なおテキスト用は

android:drawable

のところを

android:color

に書き換えてやるだけ. ってゆーかdrawableが無い.

2. 実装

用意ができたらいざ実装. selectorを使いたいボタンに対して,

 android:background="@drawable/背景用selector"
 android:textColor="@color/テキスト用セレクター"

と指定してやるだけ. これで後は何もせずとも勝手に色を変えてくれます.

またしてもちなみにラジオボタンで使う場合.

android:button="@null"

してやらないと, ラジオボタンの
こいつ('A`)
が居座り続けるという大惨事に.


画像が使いにくい…(・ω・`)

2012年11月8日木曜日

Androidでアプリの背景色にグラデーションを使用する

私用アプリの作成中ふと思う

「背景寂しいなぁ…」

とか呟いていたら割と予想外の出会いを果たしたのでメモメモ


グラデーションを利用する


1. 始めの色, 終わりの色の作成

グラデーションというからには ある色 から ある色 へと変化するので, その始めの色と終わりの色を作成する. 
場所は res/values/color.xml にでもまとめておくといいかと. 無ければ作れば良い.


2. グラデーションの指定

色が決まったらいよいよグラデーションの指定.
res/drawable ディレクトリにお好きな名前で.xmlを作成する

<?xml version="1.0" encoding="utf-8"?>
<shape  xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient android:startcolor="@color/color_back_gradient_start"
        android:endcolor="@color/color_back_gradient_end"
        android:angle="315">
    </gradient>
</shape>

colorは自作の色.
<shape>では背景に関していじることができる模様

android:shape="rectangle"

で形状を指定. この場合は長方形になる
ちなみに oval を指定すると楕円形になります.

そして<gradient>でそのグラデーションの内容の指定を行なう.

android:startcolor="@color/color_back_gradient_start"
android:endcolor="@color/color_back_gradient_end"
android:angle="315"

このあたりは見たとおり. 上から グラデーションの始まりの色, 終わりの色, グラデーションをかける角度 を指定している.
注意は3つ目の角度. この角度はの基準は 左→右 である点に注意. なので 0 を指定すると左から右へのグラデーション. ここから角度を増やすと反時計回りにぐるぐる回りだす.
またこの角度, 指定できるのは 45 * n である数値のみである点にも注意. 負の値を入力すると逆回転します.

3. グラデーションの配置

作った.xmlを書くwidgetの android:background に指定してやればOK.
ね?簡単でしょう?



ちなみに<shape>には他にも 角をいじる<corners>や, 枠線をつける<stroke>等があるらしいけど, 今回はいじってないのでまたの機会に





顔文字使ってねぇ!Σ(・д・)

2012年11月1日木曜日

androidのアプリケーション名の落とし穴

「アプリケーション名がStrings.xmlのapp_nameで出てこない」
こんなことを言われたのが先日.

「そんなんManifestの<application>にandroid:labelタグで設定されてるやん」
とか調子こいていたのもつかの間


「app_nameが出てこない…( ゚д゚ )」



ということで今回のお題

ランチャーに表示するアプリケーション名の設定場所


結論から言うと原因はManifestの<intent-filter>
ただしこいつは悪さをしていたわけではなく, むしろ一生懸命仕事をした結果が原因らしい.

通常アプリを開いて最初に開きたいActivityには, Manifestにて

<intent-filter>
    <action android:name="android.intent.action.MAIN"/>

    <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>


と宣言するはず.
すると, この<intent-filter>, こいつがランチャーに表示する名前を探し出す.
問題はこの時, <application>へ探しに行ってくれれば良いのに,

まず自分
  ↓
無ければ自分を含むActivity

の順に探そうとする.
結果, 名前を指定してやらなかったことが災いして, Activityにつけた名前を
「これがアプリケーション名だ!+(゚∀゚ 0)*」
とうれしそうに表示するわけですよ.
それじゃない…それじゃないんだ…!

なので

<intent-filter
    android:label="@string/app_name">
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

といった形で, <intent-filter>のlabelで教えてやると, 望んだとおりのお仕事をしてくれます.





ちなみに  自分を含むActivity にすらlabelが無かった場合, 表示するのは
そのActivityのパッケージ名 + Activity名
…そりゃねぇよorz
<application>さん使ってやれよ…

11/19訂正: ちゃんと<application>から取ってきてくれるみたいですorz
もうやだこのIS03

AWS CDKで立てたEC2インスタンスのTimeZoneとかいじりたかった話

EC2を立てることはできたけど、立てたインスタンスは UTCのままだし設定ファイルとかいちいちscpしてくるのはダルい。 当初UserDataでなんとかしようとしたものの、「書く量がヤバいしメンテしにくい」と悩んでいたところ見かけたのが  AWS::CloudFormation:...