怪奇現象が色々発生した
- maxLinesとか指定するとずれる
なんだか2行目の文字が1行目に食い込んだりする
- 消える
もはや表示されない。
- 端末によって挙動が違う
消えたり、消えなかったり、ずれたり、ずれなかったり
噂によるとheightをしてしたり、layout_gravityにtop|bottomを指定するといいらしいけど効果がなかった。 なんじゃこりゃ・・・
怪奇現象が色々発生した
なんだか2行目の文字が1行目に食い込んだりする
もはや表示されない。
消えたり、消えなかったり、ずれたり、ずれなかったり
噂によるとheightをしてしたり、layout_gravityにtop|bottomを指定するといいらしいけど効果がなかった。 なんじゃこりゃ・・・
フォントを変更した場合には一手間加える必要がある
参考
http://dev.classmethod.jp/smartphone/android-font-fit-text-view/ https://gist.github.com/STAR-ZERO/2934490
mPaint.setFaceType(getFaceType()) // フォントをPaintオブジェクトに渡してあげる
mPaint.setTextSize(textSize);
これをやっておかないと、違うフォントでサイズを取ってしまうのでずれる。 あと高さをwrap_contentにすると、調整処理が入った場合二行以上になってからサイズが調節される関係で高さがおかしくなるのでTextViewの高さは指定しておいたほうがいい。
API Level9以降(2.3)ならCaligraphyを使う
chrisjenx/Calligraphy · GitHub
マテリアルガイドラインによると、RobotoフォントとかNotoフォントを使えって書いたある。 ちょろっと調べて思い浮かんだ疑問
assetsにファイルサイズ制限があるのはAPI Level8まで。 ソースコード漁ってもAPI Levet9以降のasste.hにはUNCOMPRESS_DATA_MAXは存在しなかった。
こういうの
この方法は間違ってないし、このTextViewが大量に生成されなければ大した問題じゃない。 が、ListViewとかで使ってしまうと大変なことに。いくらViewがリサイクルされると言っても画面内に同時に表示される分はTextViewが作られるので、その分だけassetsからフォントを読み込んでFaceTypeオブジェクトが作られまくってる(多分)。4.4の端末でOOMで落ちたの久しぶり。
できれば一度読み込んだFaceTypeはActivityかApplication辺りでキャッシュしておきたい。 各TextViewではそれらを使いまわすのが理想。っていうか後からTextViewを全部オリジナルのTextViewに書き換えるの面倒くさい。名前空間の宣言すら面倒くさい。
唸ってたら同僚からこんなこと書いてあるよってQiitのページを教えてもらった。
font - AndroidでNotoフォント・Robotoフォントを使う - Qiita
Caligraphy。そういうのもあるのか。 使い方を見るとすごく簡単そう。何やってるか気になったので簡単にソース読んでみたのでその内容をざっくりまとめます。 使い方は↑のサイトとかCaligraphyのgithub見るといいと思います。
attachBaseContextをオーバーライドして、CalligraphyContextWrapperでcontextをラップしてる。 これはContext.getSystemService()をオーバーライドする為にやっているようだ。 こうすることで、LAYOUT_INFLATER_SERVICEが呼ばれた時に、CalligraphyLayoutInflaterを使用するようになる。
CalligraphyLayoutInflaterの内部でinflateされるViewがTextViewだった場合にFontがセットされているようです。 また、TypeFaceもActivity毎にキャッシュされているので、ListViewで大量にTextViewが生成されてもロードされるのは1種類につき1回だけですね。
最悪自分で実装しようと思ってたので、こんだけドンピシャなライブラリがあったのは僥倖でした。 FAQに「カスタムIDを使うのにaarを使う必要があるから、jarでは提供しないよ、っていうかGradleつかってないの?」って書いてある点も個人的にポイント高めです。 「android TextView custom font」とかでググっても出てこなかったのが残念。っていうか古い情報ばっか出てきて混乱した。僕は全然知らなかったんですが、Calligraphyって有名なんですかね?日本じゃ有名じゃないだけなのか、僕が知らないだけなのか・・・もうちょっと情報収集頑張らねば
どうも、バグを生み出すプロ、しんばしさんです。
非同期のHTTP通信ライブラリのVolleyを使用していたのですが、302リダイレクトするAPIへアクセスしたところ com.android.volley.NoConnectionError: java.io.IOException: Could not retrieve response code from HttpUrlConnection
とかでてうまく動きませんでした。開発機では問題なかったのですが、ロードバランサを経由する本番機では発生するという状態。ロードバランサ経由の場合HTTP/1.1でリクエストするとConnection:keep-aliveをヘッダで返してくるというのが原因でした。
解決策としては HurlStack を利用していた部分をこちらのGistを参考にOkHttpClientを使う自作のHttpStackを使うように切り替えて解決。
以下だらだらとそこまでの経緯。
VolleyはGingerbread以前ならHttpClient、それ以降はHttpURLConnectionを内部的に使っています。今回はVolleyに含まれているHurlStackを使っていたのでHttpURLConnectionを使っていました。minSdkVersionもICS以降なのでHttpURLConnectionのバグも解消されているハズ・・・!と思っていたらそうでもありませんでした。
今回の原因はHttpURLConnection.getResponseCodeが呼ばれる時にレスポンスヘッダにConnection: keep-aliveが含まれているとそこでIOExceptionが発生してしまうことでした。なんかandroidはkeep-aliveにまつわるバグが多い割にデフォルトでkeep-aliveはtrueなのだとか。
System.setProperty("http.keepAlive", "false");
とりあえず上記のコードを呼んで見たけど効果なし。ぐぬぬ。 バージョンが上がって過去にあったバグが直った!とか言われてますが、HttpClientもHttpURLConnectionもどうも期待した動きをしてくれない模様。なので今後はOkHttpClientを使っていこうかなぁ・・・。
リクエスト時にHTTP/1.0でリクエストするようにしたHttpStackを作るというのも考えましたが、なんかわざわざ古い方に合わせるのも気持ち悪いので却下。
バージョンによってバグがあるからHttpClientとHttpURLConnectionが使い分けられるのも、今後発生するかもしれないバグの見極めがむずがしそうなので、今回はOkHttpClientを使って自作のHttpStackを使うという結論に至りましたが、なんか他にいい方法ないかなぁ・・・。
https://gist.github.com/bryanstern/4e8f1cb5a8e14c202750
OkHttpStack stack = new OkHttpStack(new OkHttpClient()); RequestQueue = Volley.newRequestQueue(context, stack);
どうもわたくしです。
TextViewの高さを超えてテキストがセットされていたら、ボタンを出したい。 ボタンを出したいんです。
こんなかんじにTextViewを超えて長文が入力されていたら
ボタンを出したい。
行数 > 最大行数(TextViewの高さ / 1行あたりの高さ)でよさそう
final TextView textview = findViewById(R.id.textview); textView.post(new Runnable() { @Override public void run() { Layout layout = textView.getLayout(); if (layout != null) { int lines = layout.getLineCount(); int max = (int)(textView.getHeight() / textView.getLineHeight()); if (lines > max) { findViewById(R.id.button).setVisivility(View.VISIBLE); } } } });
こんな感じ。 行の高さとかViewの高さはレイアウトされてからじゃないと取得できないので、post()を使ってレイアウト後に処理を行えばおk
別にルイズコピペを使いたくてこの記事を書いたわけじゃないよ、ほんとだよ。
MD5やらSHA-256でハッシュ化したい機会ってのはよくあると思うんですが、ググるとなんでかMessageDigestクラス使って長々と記述するサンプルが多く見かける気がします。 ラップしたクラスを作ってもいいんですが、せっかくだから俺はcommons-codec使うぜ!
gradleに追記
compile 'commons-codec:commons-codec:1.10'
コード
String hash = DigestUtils.sha256hex("abc");
うんうん短くてよきかなよきかな
Could not find method org.apache.commons.codec.binary.Hex.encodeHexString, referenced from method org.apache.commons.codec.digest.DigestUtils.sha256Hex
そんな気はしてた。 どうやらDigestUtilsが内部で使ってるHex.encodeHexStringが無いということらしい。どういうことなの。 試しに名前空間を変えて、org.apache.commons.codec.binary.Hexの中身をまるっとコピーして実行するとうまくいった。多分android SDK が内部的にcommons-codec使ってて、そっちにあるHexが呼ばれているっぽい。Google Playアプリのライセンスの中にもcommons-codecってあるし多分そういうことなのだろう。 とりあえず、encodeHexStringが使われないようにしてお茶を濁そう。
String hash = new String(Hex.encodeHex(DigestUtils.sha256("abc"));
敗北感ある・・・(´・ω:;.:...
大体皆さん "android フォント 自動" "android Textview 横幅" とかでググって、TextViewを継承したクラスの実装を見かけたと思います。
参考
http://dev.classmethod.jp/smartphone/android-font-fit-text-view/ https://gist.github.com/STAR-ZERO/2934490
この2つの実装の違いはonMeasureかonLayoutでやってるかの違いですが、それはまあ置いておいて。 これらをListViewの内部で使おうとしたら残念な結果になってしまいました。 もしくはListViewじゃなくても、setTextを繰り返し行う場合には同じ結果になるかもしれません。
以下の手順を同じtextViewに行います
setText後にsetWidthを呼ぶ
textView.setText(text); textView.setWidth(getContext().getResources().getDimensionPixelSize(R.dimen.width));
テキストサイズの調整をonLayoutもしくはonMeasureで行っているので、当然onLayout, onMeasureが呼ばれなければリサイズされません。
setTextI()を呼んでonLayoutが走るのは 現在のwidthよりも大きいサイズのテキストがセットされた時
だけのようでした。そのため、現在のwidthに収まる範囲のテキストをセットしてもonLayoutは呼ばれません。
本来はレイアウトを設定し直す必要がないので当然ですが、今回は毎回呼んでもらわないと困るので、強引に元からセットしてあるwidthと同じ値を再度セットすることで強引にonLayoutを呼び出すことで解決しました。
なんか他にonLayoutを走らせるいい感じのメソッドがあるかもしれませんが調べてません。
おわり。