2014年6月25日水曜日

【Android】めだったー つかいかた

1.めだったーとは

めだったーはTwitterで埋もれがちなつぶやき全力で目立たせるための無料Androidアプリです.
ダウンロードはこちらから
つかいかたは
・フレームを選ぶ
・文字を入力する
・完成
の3ステップです.

できるだけ目立たせるために文の長さに合わせて文字サイズを自動調整して
一番大きいサイズで作成します.
短い文なら目立たせるためにとにかく文字を大きく

文が長くなると文字サイズを自動調整して全文入れるようにがんばります!


2.つかいかた

めだったーの使い方は前述したとおり,簡単ですが
好みで色などを調整できるのでそこを中心に説明します.

・フレームの選択

好みのフレームを選択してください.
それだけです.

・背景色の選択

背景色を好みに合わせて変更できます.

左上のボタンを押すと背景色が選べます.
左上のボタンで背景色が選べる
背景色を変更できた!

・文字色の選択

文字色を好みに合わせて変更できます.

文字入力欄を長押しすると文字色が変更できます.
文字入力欄を長押しすると文字色が変更できる
文字色が変更できた!
文字の縁取りの色は文字の色の濃さによって自動で調整されます.
文字サイズも変更できますが,アプリの趣旨的には全力で目立たせることなので最大値(60)をオススメします.

 

・画像の調整

フレームによってはスマートフォンに保存している画像をはりつけることのできるものもあります.

ここを長押し~と書いてある部分を長押しすると
画像を選択できます.
画像を選択して貼り付けられる!
位置を修正したい場合は2本指でドラッグしてください.
サイズが気に入らない場合は2本指でピンチイン・ピンチアウトしてください.
画像を選びなおす場合は再度画像の部分を長押しすると選び直せます.

・完成させる

完成の前にまずはプレビューしてどうできあがるかを見てみましょう.
左上のプレビューボタンを押してください.
色や出来上がりを確認できます.

プレビュー中は編集できません.編集し直すには左上の編集ボタンを押してください.

これでよければ右上の生成するボタンを押すと完成です.
画像が生成され,スマートフォンに保存されます.
他のアプリで開くを選んでTwitterにつぶやこう!


3.一例

こんなものが出来上がります.
俗悪な眠気をみんなに
教えてちゃんにリプライ
在庫の山ははけるのか

2014年6月12日木曜日

【Android】追記・画像をぴったり繰り返す考え方

さっきのエントリはあのまま使って嬉しい事はあまりないよね.
だからあれはああいうアイデアだから.
ソースコードもあのまま使えばいいって話じゃない.

あの考え方を転用するとこういうViewが作れる.
ほんとうはこれがやりたかった.
画像は適当に分かりやすそうなものを作った.
こんな画像だと中途半端に繰り返すと角の画像とずれるでしょ?

こういうダイアログも作れるよという例.

これをNinePatchとともにSDK側で用意してくれてると助かったんだけどな.

【Android】画像をぴったり繰り返すアイデア

前回のエントリではBitmapDrawableのsetTileModeXYメソッドを使って
画像の繰り返し配置を実現したけど
それだけじゃ一番端が切れてしまう.
前回のRepetitiveImageViewに分かりやすいように

この画像を適用させて表示した結果が以下のとおりである.


一番右端の子が途中で切れてしまっている.
特に問題ないことが多いと思うが,
どうしてもキッチリ収まってないと気になってしまう人へ

こんなアイデア.
タイル画像のサイズとView自体のサイズを取得し
繰り返す回数を計算する(Viewサイズ÷タイル画像サイズ)
余白(Viewサイズ%タイル画像サイズ)を繰り返す回数で割って
余白分だけ大きくなるようにタイル画像を少し拡大する

例を出すと
Viewの幅が100で
画像の幅が30だと仮定する.
まず繰り返す回数を計算する
100÷30 = 3
余白は100 % 30 = 10
この10を繰り返す3枚分に分け与えて
画像サイズを33.3333…にする.
そうすれば3回繰り返すと99.9999…となって
余白なく繰り返すことができる.

ん?33.3333…?
画像サイズが33.3333…?

ここで破綻する.
画像サイズはint値なので.33333なんてものは認められない.
また,TileModeの設定上全て同じサイズになるので
1枚だけ34で残り2枚を33なんて器用な真似はできない.

小数無視すればいいじゃんと考えるかもしれないが
計算しやすいように100と30という値を選んだが,
繰り返し回数が10回とかいう実際の環境だと
丸めた小数はバカに出来ないくらい大きくなり
数ピクセルの誤差が出てしまう.

じゃあ別の方法を採るしかない.
というわけで別案.
いわゆるゴリ押し.

NewRepetitiveImageViewというクラスを作ったが,
ImageViewはもはや関係もないLinearLayoutのサブクラス.

考え方としては上記のモノを引き継ぐのだが
タイル画像のサイズとView自体のサイズを取得し
繰り返す回数を計算する(Viewサイズ÷タイル画像サイズ)
ここまで一緒
繰り返し回数分LinearLayoutに子Viewを追加して
そのViewの背景画像としてタイル画像を設定
LinearLayoutには子Viewのサイズを等分割するモードがあるので
あとはLinearLayoutまかせ
という方法.

ソースコード例としてはこんな感じになる.

凄まじく御丁寧にコメントを書いたので内容はそっち読んでね.
GlaphicalLayoutが役に立たないよ.

使い方はレイアウトXMLに配置して
android:backgroundに繰り返したい画像をセットするだけ.
で,実機での動作が以下のとおり.

上が今回のNewRepetitiveImageViewで
下が前回のRepetitiveImageView.
今回のViewは枠にぴったり収まってるのがわかるね.


これダイアログの枠とかで実用的だと思うんだ.
9patchだと繰り返しができないからね.

今回は横に並べたけど
縦に並べることもできる.
OrientationをVerticalにして
widthとheightでやってることを入れ替える.

縦横配置は…
やめたほうがいい.

前回できたMirrorタイル配置はこのままではできないけど
ソースコードでBitmap展開して反転してってやるより
画像のほうで対応したほうが楽だよ.

2014年6月11日水曜日

【VR】モビルスーツの当たり判定

モビルスーツに限った話ではないが
全天周囲モニター搭載コックピットを持つ大型兵器
こいつの当たり判定(っていうか実体なんだけど)って
モニターで見るよりも広いよね.

ギリギリで避けたつもりでいたら右足が持って行かれたとか
そういうのがありそう

車だとモニターじゃなくて実風景だし
自機のボンネットがみえるからどこまで自機かというのが視覚的に把握しやすいけど
全天周囲モニターだとそういう描写がない.
人間だと自分の肩が見えるわけ.
鼻も見えるし脚も見える.
でもMSでは自機が部分的にも映るということがほとんどない.
サーベル振ったり人を乗せたりで手が前に来たときくらい?
肩や脚が映ることってないよね.

そりゃあ全天周囲モニターで下を向いたら自機の胴体で見えませんでした
なんてのは意味がないわけ.

何が言いたいかっていうと
Oculusなど向けにVRゲームを作る際に
全天周囲モニターがどのように撮影をして
どのようにモニターにマッピングしてるかを考慮しないといけないんじゃないか
ということ.

ザクみたいに一部だけが見えるってのも別にいいんだけど
せっかくヘッドトラッキングしてくれるんだから
顔の向きに合わせて様々な方角が見えたほうが楽しい.

頭部にカメラがあって胸部にコクピットがあるとする.
細いビームが直線的に頭部に向かっているのに
パイロットには胸部にビームが飛んできていると錯覚する.
バックパックのバーニアの向き的に脚方向への移動より
頭方向への移動のほうが瞬間的に反応してくれるので
バーニアをふかして頭の方に避けようとしたけど
余計にコクピットに直撃するコースになった.
そういうことにもなりかねない.

光学カメラは多種レーダーのうちのたった一つ
という場合で,
コクピットの位置が相対的に正しく表示されると仮定する.
上の例で言えばコクピットの少し上を狙って細いビームが飛んで行く
そんな場合でも一番最初に言った当たり判定がコクピットの大きさ以上にある
よかった,これは少し上を外すコースだ!と思ったら頭が吹き飛んだ.ってなりそう.
ということを前提に実装しないといけない.

自分がロボットになる
という場合は別に影響ないけどね.

【Android】画像を繰り返すImageView

先に言っておくけど別にImageViewじゃなくてもいいんだからね.

さて,ImageViewってのは指定した画像を1回だけ表示するものなんだよ.
ImageView::scaleTypeの指定によって
ImageView自体の大きさに画像をどうフィットさせるか/させないかを
指定させることはできても
Viewの中に表示される画像は1回だけなのね.
タイル配置みたいな繰り返し表示はできない.

9patchなんてものを大きく打ち出してカバーしてる一方で
androidってタイル配置に関してはそのままでは実現できない.

9patchは確かに便利なんだけど
時と場合によるよね.
繰り返しパターンには向いていない.

そこでタイル配置を実現するために
/res/drawable配下にXMLを作って
<bitmap>を作ろうっていうのがたくさん散見されるので
その場合はそちらを参考に.
新しく書く必要もない.

かといってこのエントリも新しく書く必要があるのかどうかと問われると微妙なんだけどね.

やっぱりレイアウトXMLにViewを配置して
画像リソースを指定したらタイル配置画像が表示される
っていうのがやりたいやん?
タイル画像がたくさんある場合に画像の数だけXMLがdrawable下に増えてくるのも鬱陶しいやん?
という個人的なワガママを個人的に解決.スッキリ

ImageViewを継承したRepetitiveImageViewなんていうものを作ってみた.
といっても大したことをしていないので見てほしい.


ソースの半分を占めるコンストラクタなんだけど
自作Viewを作るときはいつもこの3つをちゃんと宣言するようにしている.
引数1のコンストラクタがないとソースコードで扱う場合に面倒だし

楽:CustomView customview = new CustomView (this);
嫌:CustomView customview = new CustomView (this, null, 0);
毎回こんなの書くの嫌だよ.

引数2のコンストラクタがないとレイアウトXMLに配置したときに
GraphicalLayoutがエラーを返す.
引数3のコンストラクタは自分では基本使わないけど
何かの時に何気にやくにたつかもしれない
ということで毎回全部実装しているよ.
といっても今回は親クラス(ImageView)のコンストラクタに丸投げするだけで
なにもしていないけどね.

setImageDrawableは親クラス(ImageView)のオーバーライド.
でも親クラスのsetImageDrawableは呼び出していないよ.
見ての通りImageViewの前景画像として飛んできたDrawableを前景画像として使わずに
奪って背景画像として使っているよ.
その際にDrawableを一旦(Drawableのサブクラスである)BitmapDrawableにキャストして
BitmapDrawableのsetTileModeXYというメソッドを使ってタイル配置を実現している.

背景画像として表示しているため
最初に言ったとおり別にImageViewでなくてもViewであればなんでもいいんだよね.
FrameLayoutとかのViewGroup系でもいい.
タイルで嬉しいのは
ボーダーか背景かだと思うので
背景として使う場合はViewGroup系がいいんだろうね.
その場合はこのコードでやってることを
setBackgroundDrawableとかでやるといいんじゃない(適当)

で,使い方は
レイアウトXMLに

こんなかんじで使ってやればOK.
画像はこの画像を使ったよ.

そしてこの結果は以下のとおりになるよ.

もし↓のように書き換えると

こうなる.


両方ともmatch_parentにすると

こうなる.

圧巻

それだけで終わるのもなんなので,
setImageDrawableで指定している
d.setTileModeXY(TileMode.REPEAT, TileMode.REPEAT);

d.setTileModeXY(TileMode.MIRROR, TileMode.MIRROR);
こうすると

反転タイルになる.



TileModeにはもうひとつ,
TileMode.CLAMPなんていうものがある.
このモードがわかりやすいように使う画像を

これに変更.
CLAMPモードは画像端が引き伸ばされる.

(これやったら9patchでええやん)

2014年6月6日金曜日

【Android】テキストサイズが端末によっておかしくなる場合があるときに

Androidアプリには
/res/values/dimens.xml
という数値(サイズ)を一括で設定しておくファイルがある.


Viewの幅,高さややフォントサイズなど
ソースコード内にサイズをマジックナンバーで書くのは躊躇われる.
そんなときにこのdimens.xmlに記述して各レイアウトファイルやソースコードから呼び出す.

上で数値(サイズ)と書いたが,
ただ単なる数値(データ)は別のリソースxmlにintegerをどうぞ.

この/res/values/dimens.xmlはプロジェクト生成時に作られてるはず.
見てもらうとDIPやSP,PX等単位をつけることができるのが分かる.

dimens.xmlに記載された値をソースコードから取得するには
getDimension()やgetDimensionPixelSize()といったメソッドを使うのだが,
以下の例のような点に注意してほしい.

例:
・/res/values/dimens.xmlで↓のように定義する
 <dimen name="hoge16dip">16dip</dimen>

・Javaからそれを取得する
 getDimension (R.dimen.hoge16dip);

このときgetDimensionして得た値は16ではない(可能性が高い)

getDimensionすると,画素密度に応じてピクセルサイズに直してくれ,
その値が取得できるのである.
つまり,得られる値は以下のとおりである.
mdpi(1x): 16
hdpi(1.5x): 24
xhdpi(2x): 32
xxhdpi(3x): 48
取得できる値は画素密度倍率を計算済みのピクセルだ.

16DIPのリソースをgetDimensionして16が得られるのは端末がmdpiのときのみである.

これはバグか?
いいや,これが正しい動きなのである.
端末の解像度の差異を気にしなくていいため
このほうが殆どの場合で嬉しい動きなのだ.
そうでないとgetDimensionでサイズ値を取得した後に
画素密度倍率を取得,表示すべきサイズを計算しなくてはいけなくなる.

ちなみにフォントサイズを指定するときに推奨されている単位はDIPじゃなくてSP.
このSPという単位はDIPにさらに端末のフォントサイズ設定を反映させたもの.
これがさらに問題をややこしくさせる場合がある.
今回はとりあえず(゚ε゚)キニシナイ!!

ここまでを踏まえて以下のことに注意してほしい.
TextView::setTextSize(float size)というテキストのサイズを指定するメソッドは
このままでは引数をSP値として扱う.

<dimen name="hoge16sp">16sp</dimen>
というリソースに対して

float size = getDimension (R.dimen.hoge16sp); // テキストサイズだから16SPにしてるよ
textView.setTextSize(size);

↑こんなことはしてはいけない.

全て画角を5インチに合わせてプレビューを作ってみた.
同じ5インチでも解像度が高くなると画素密度も高くなる.
見ての通り画素密度があがるにつれフォントが大きく見えるようになる.
(何故かXXHDPIでは文字が崩れた)
こんなのでは実用に耐えない.





解決方法は
TextView::setTextSize(int unit, float size)メソッドを使うこと.
先に述べたとおりgetDimensionで得られる値はその端末用に計算されたピクセル値なので
ここでunitにTypedValue.COMPLEX_UNIT_PXを指定する.

float size = getDimension (R.dimen.hoge16sp);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);

これで端末解像度が変わってもサイズはあまりかわらないようになった.