ひらい ぶらり Hi-Library

ぷろぐらみんぐについて。ときどきどうでもいいことについて。

TextViewで縦にはみ出してるかどうかを検知したい

どうもわたくしです。

TextViewの高さを超えてテキストがセットされていたら、ボタンを出したい。 ボタンを出したいんです。

f:id:shin_bashi:20150326011934p:plain

こんなかんじにTextViewを超えて長文が入力されていたら

f:id:shin_bashi:20150326011956p:plain

ボタンを出したい。

解決編

行数 > 最大行数(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

別にルイズコピペを使いたくてこの記事を書いたわけじゃないよ、ほんとだよ。

Android で MD5とかSHA-256とかするのにcommons-codec使おうとしたらエラーが出た話

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"));

敗北感ある・・・(´・ω:;.:...

フォントサイズ自動調整TextViewをListViewで使いたい

大体皆さん "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に行います

  1. 横幅を超えないテキストをセットする→期待どおり
  2. 横幅を超えるテキストをセットする→期待通り
  3. 再び横幅を超えないテキストをセットする→ 2.のサイズから戻らず小さいまま

解決策

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を走らせるいい感じのメソッドがあるかもしれませんが調べてません。

おわり。

ImageViewの明度、コントラスト、彩度、色相をObjectAnimatorでアニメーションする

タイトルのようなことをしたかったんですが、そんなプロパティはなかったのでImageViewを拡張してプロパティをつけたら出来ました。

↓のようなクラスを作って、xmlなり動的に生成するなりしたImageViewに対して操作をすれば期待した動きをしてくれる。

public class ExtendedPropatyImageView extends ImageView{

    private static final float[] defaultValues = {
            1, 0, 0, 0, 0,
            0, 1, 0, 0, 0,
            0, 0, 1, 0, 0,
            0, 0, 0, 1, 0
    };
    private int mBrightness = 0;
    private float mContrast = 0f;
    private float mSaturation = 0f;
    private float mHue = 0f;
    private int mRed = 0;
    private int mGreen = 0;
    private int mBlue = 0;

    public ExtendedPropatyImageView(Context context) {
        super(context);
    }

    public ExtendedPropatyImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setBrightness(int brightness) {
        float[] values = defaultValues;
        ColorMatrix matrix = new ColorMatrix();
        values[4] = values[9] = values[14] = brightness;
        setColorFilter(new ColorMatrixColorFilter(values));
        mBrightness = brightness;
    }

    public int getBrightness() {
        return mBrightness;
    }

    public void setContrast(float contrast) {
        float[] values = defaultValues;
        values[0] = values[6] = values[12] = contrast;
        setColorFilter(new ColorMatrixColorFilter(values));
        mContrast = contrast;
    }

    public float getContrast() {
        return mContrast;
    }

    public void setSaturation(float saturation) {
        ColorMatrix matrix = new ColorMatrix();
        matrix.setSaturation(saturation);
        setColorFilter(new ColorMatrixColorFilter(matrix));
        mSaturation = saturation;
    }

    public float getSaturation() {
        return mSaturation;
    }

    public void setHue(float hue) {
        float[] values = defaultValues;
        float a = Math.max(0, (float) Math.cos(hue / 360 * 2 * Math.PI));
        float b = Math.max(0, (float) Math.cos((hue - 120) / 360 * 2 * Math.PI));
        float c = Math.max(0, (float) Math.cos((hue - 240) / 360 * 2 * Math.PI));
        float sum = a + b + c;
        values[0] = values[6] = values[12] = a / sum;
        values[1] = values[7] = values[10] = b / sum;
        values[2] = values[5] = values[11] = c / sum;
        setColorFilter(new ColorMatrixColorFilter(values));
        mHue = hue;
    }

    public float getHue() {
        return mHue;
    }

    public void setRed(int red) {
        float[] values = defaultValues;
        values[4] = red;
        setColorFilter(new ColorMatrixColorFilter(values));
        mRed = red;
    }

    public int getRed() {
        return mRed;
    }

    public void setGreen(int green) {
        float[] values = defaultValues;
        values[9] = green;
        setColorFilter(new ColorMatrixColorFilter(values));
        mGreen = green;
    }

    public int getGreen() {
        return mGreen;
    }

    public void setBlur(int blue) {
        float[] values = defaultValues;
        values[14] = blue;
        setColorFilter(new ColorMatrixColorFilter(values));
        mBlue = blue;
    }

    public int getBlue() {
        return mBlue;
    }
}

アニメーションさせるときはこんな感じ

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ExtendedPropatyImageView image = (ExtendedPropatyImageView) findViewById(R.id.image_view);
    ObjectAnimator objectAnimator = ObjectAnimator.ofInt(image, "brightness", 0, 255);
    objectAnimator.setDuration(1000);
     objectAnimator.start();

}

後は値の型に合わせてofFloatにするなり、brightnessをhueやらに変えればそのプロパティを変更するアニメーションを実行することが出来た。

ColorMatrixクラスに彩度をセットするメソッドはあったけど、なんで他は無いんだろう・・・

Android Studio を 0.8.14 にアップデートしたら「The Android SDK folder can no longer be inside the application folder.」とか言われた

こんにちはこんにちは

久しぶりにAndroid Studioを起動することになったらアップデートが来てたので、作業後にアップデートしてみることに。

f:id:shin_bashi:20141031212849p:plain

なんか出た。

んー、SDKフォルダをApplicationsに置くなということらしい。詳細を見てみると本来はそういうとこに置くもんじゃないでしょ、的なことが書いてある。

いや、それはそうなんだけど、そこに配置してたのは(ry という言葉はぐっと飲み込み言われる通りに

mv /Applications/Android Studio.app/Contents/sdk ~/

適当にUsers以下とかに移す。

Retryを押す。進む。

当然の如くSDKのパスが変わっているので、起動するとSDKはどこだ!って言われる。

f:id:shin_bashi:20141031215614p:plain

他にもSDKを使ってるツールがアレばひと通りパスを修正してあげましょう。

終わり。

androidで強制的にChromeで開くリンク

<a href="intent://yahoo.co.jp#Intent;scheme=http;action=android.intent.action.VIEW;package=com.android.chrome;end
">Chromeで開く</a>

このリンクを開くアプリケーションがまともな実装をしている場合に限り、http://yahoo.co.jpが開かれるっぽい。 Operadで実験してみたところ成功したけど、全てのアプリで起動するかわWebViewClientの実装によるので絶対とはいえないのが切ないところ。

そして、使いどころもよくわからない。