スポンサーリンク

2016年11月24日木曜日

Android でテキストをブリンクさせる

意外なことに Android にはテキストをブリンクさせる機能がありません。

なのでアニメーションを使ってブリンクさせる例をよく見かけます。例えばこんな感じ。

        Animation animation = new AlphaAnimation(0.0f, 1.0f);
        animation.setDuration(1000L);
        animation.setRepeatMode(Animation.REVERSE);
        animation.setRepeatCount(Animation.INFINITE);

        View textView = findViewById(R.id.text_view);
        textView.startAnimation(animation);

Android 3.0 以降であれば ObjectAnimator を使って、以下でもよいでしょう。

        View textView = findViewById(R.id.text_view);
        ObjectAnimator animator = ObjectAnimator.ofFloat(textView, "alpha", 0.0f, 1.0f);
        animator.setDuration(1000L);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.REVERSE);
        animator.start();

しかしアニメーションを使う方法は値を連続的に変化させるのでCPUに負荷がかかり、ブリンクさせている間中ずっとこの負荷がかかり続けます。この点がどうも気になります。



パソコン端末でサポートしているANSIエスケープシーケンスのブリンク機能は、多くの場合、単にオン/オフを切り替えているだけです。なのでこれと同じ仕組みを作ってみました。

せっかく作るのであれば全てをカプセル化し、専用の BlinkTextView にしてみました。Handler の遅延実行機能を使って定期的にオン/オフを繰り返すだけです。これであれば負荷は最小限で済みます。

public class BlinkTextView extends TextView {

    private static final int MESSAGE_CODE = 100;

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MESSAGE_CODE) {
                mVisible = !mVisible;
                if (mVisible) {
                    setAlpha(0.0f);
                } else {
                    setAlpha(1.0f);
                }

                if (mBlinking) {
                    sendEmptyMessageDelayed(MESSAGE_CODE, mInterval);
                }
            }
        }
    };

    private boolean mBlinking = false;
    private boolean mVisible;
    private long mInterval = 500L;


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

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

    public BlinkTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    public void startBlinking(long intervalMillis) {
        // Do nothing if already blinking
        if (mHandler.hasMessages(MESSAGE_CODE)) {
            return;
        }

        mInterval = intervalMillis;
        mBlinking = true;

        mHandler.sendEmptyMessageDelayed(MESSAGE_CODE, mInterval);
    }

    public void stopBlinking() {
        mBlinking = false;
        mHandler.removeMessages(MESSAGE_CODE);
    }
}

ブリンクをスタート、ストップするには startBlinking(), stopBlinking() を呼び出します。二重起動しないようにとか、多少の工夫をしています。

使い方は、例えば Activity からであれば以下の様に呼び出します。Fragment でもほぼ同じです。

public class MainActivity extends AppCompatActivity {

    private BlinkTextView mBlinkTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBlinkTextView = (BlinkTextView) findViewById(R.id.blink_text);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mBlinkTextView.startBlinking(700L);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mBlinkTextView.stopBlinking();
    }
}

忘れがちなのが、View が非表示中にブリンクを止めることです。非表示中に虚しい作業を繰り返しても意味がありません。onPause() でブリンクを停止、onResume() で開始しています。この部分もできればカプセル化したいところですが、View の中からは表示/非表示のタイミングが分からないので、こればかりは外部から呼んでもらうしかありません。

今回の例はアルファ値を 0 と 1.0 に切り替えて、View 全体を表示、非表示させていますが、例えば背景色だけをブリンクさせるとか色々な応用ができます。

ソースコードはここに。
https://github.com/masamichi441/AndroidBlinkText

0 件のコメント :

コメントを投稿