Androidでテキストの点滅って・・・簡単じゃなかった
今日、お客さんから
「ここの文字もっと大きくして、点滅させて目立たせたいんだよね・・・」
と言われたので、たぶん、TextViewのプロパティを1箇所ポチってtrueにすればできるんじゃないか・・・てノリで探してみたが・・・
あれ? ない・・・
blinkとかが付く名前のプロパティが無いのである。えー、文字の点滅もできないの?Androidでどうやってやるんだろう?と色々調べてみました。
Animationを使う
どうやら、AndroidではAnimationという仕組みを使わないといけないらしいです。
参考URL
本家 Android developer アニメーションの概要
本家 Android developer アニメーション リソース
レイアウトエディタでTextViewのプロパティ一発ではできなくて、このAnimationの仕組みを使うらしいです。
色々な方法がありますが、一番手っ取り早くて簡単なのが、Animationのリソースを1個書いて、それを点滅させたいView(TextViewとか、Buttonとか)に適用させるのがいいようです。
Animationのリソース作る
- まず、resの下に「animator」という名前でフォルダを作ります。
- その「animator」の下にリソースを作る。「animator」を右クリックして「新規」→「Animator Resource File」
こんな画面が表示されるので、とりあえずファイル名に「blink_animation」と入れます。
xmlの中身の書き方は上の参考URLの「アニメーション リソース」を参考にしてください。とりあえず、点滅に最低限必要なものを。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="0.5f"
android:repeatCount="-1"
android:repeatMode="reverse"/>
</set>
- propertyName はアニメーションの種類。透明度を上げたり下げたりで点滅を表現するため、透明度を表す、「alpha」を指定します。
- duration はアニメーションの時間(ミリ秒単位)。デフォルトは 300 ミリ秒です。
- valueTo はアニメーションをどの値まで変化させるかの設定です。浮動小数点数、整数、色のいずれか。色の場合は 6 桁の 16 進数で表します
- repeatCount は繰り返し回数。-1は無限
- repeatMode はアニメーションが最後に到達したときにどのような動作をするか。この属性が反映されるには、android:repeatCount に正の整数または "-1" を設定します。アニメーションが繰り返されるごとに逆方向に実行するには、"reverse" に設定します。または、毎回最初からアニメーションをループさせるには、"restart" に設定します。
点滅の仕方を調整したい場合は、duration、valueToあたりを調整するといいかと思います。
MainActivity
MainActivityでViewにAnimationを適用します。
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var set: Animator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater).apply {
setContentView(this.root)
}
set = AnimatorInflater.loadAnimator(this, R.animator.blink_animation)
set.setTarget(binding.helloText)
}
override fun onStart() {
super.onStart()
set.start()
}
}
ここのミソはonCreateだけでは完結しなくて、onStartでアニメーションを開始してやらないといけいないことです。おそらく、このアニメーションの部分は非同期で裏で動いているのではないでしょうか?
しかもAnimatorのインスタンスは他のViewに使いまわしできません。点滅させたいViewが複数ある場合はその数分のAnimatorのインスタンスを作ってやらないといけません。たぶん、非同期だからでしょう。例えば、TextView1個とButton1個を点滅させてやりたい場合はこうなります。
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var set: Animator
private lateinit var set2: Animator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater).apply {
setContentView(this.root)
}
set = AnimatorInflater.loadAnimator(this, R.animator.blink_animation)
set2 = AnimatorInflater.loadAnimator(this, R.animator.blink_animation)
set.setTarget(binding.helloText)
set2.setTarget(binding.button)
}
override fun onStart() {
super.onStart()
set.start()
set2.start()
}
}
うーん・・・こうなると、なんだかレイアウトエディタのプロパティ一発でできるようにしてほしいなーと思ったりします。
最後に
完成形はgitHubに置きました