Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@KKusumi

【Android】ニコニコのコメント風アニメーションを実装する【Animation】

はじめに

デザイナー「ここボタン押したくなるようなアニメーションさせてください!」

ぼく「わかりました!」

ってことで、ニコニコのコメント風アニメーションを実装することにした。
思ったより簡単にできたので、実装方法をご紹介。

完成形

こんな感じのものを作るよ。
前提として、ルートのViewGroupはConstraintLayoutを使ってる。

やること

  1. 画面サイズ取得
  2. TextViewを生成する
  3. Y位置をランダムで設定する
  4. 生成したTextViewに制約を設定する
  5. 右から左に移動する

1.画面サイズ取得

3の「Y位置をランダムで設定」 と5の「右から左に移動」 をするのに、画面サイズが必要になる。
幅と高さ別々で取得してもいいんだけど、画面サイズのクラス作っちゃった方が僕は好み。

data class WindowSize(
    val width: Int,
    val height: Int
)

private fun getWindowSize(): WindowSize {
    val outMetrics = DisplayMetrics()
    display?.getRealMetrics(outMetrics)
    return WindowSize(
        width = outMetrics.widthPixels,
        height = outMetrics.heightPixels
    )
}

2.TextViewを生成

まずはコメントを表示させる画面に対してTextViewをインフレートさせる。

val textView = TextView(baseContext).apply {
    id = View.generateViewId()
    text = "Hello World!"
    layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
}
textView.setTextColor(Color.BLACK)
constraintLayout.addView(textView)

idはあとで使うから設定してるよ。

3.Y位置をランダムで設定

コメントが表示される高さの範囲は画面の高さ - TextViewの高さ で求められる。

これより下げちゃうと見切れちゃうからね。

val random = Random(System.currentTimeMillis())
val transitionY = random.nextInt(windowSize.height - textView.layoutParams.height)
textView.translationY = transitionY.toFloat()

乱数のシードはなんでもいいけど、今回はSystem.currentTimeMillis()を使うよ。

4.生成したTextViewに制約を設定する

設定する位置は画面の右側。

ConstraintSet().also {
    it.clone(constraintLayout)
    it.connect(
        textView.id,
        ConstraintSet.LEFT,
        ConstraintSet.PARENT_ID,
        ConstraintSet.RIGHT
    )
    it.applyTo(constraintLayout)
}

多分「何やってんのコレ?」って感じだろうけど、ConstraintSetについて調べればわかると思う。
本筋と外れるからここでは解説しないけど、@soranakk さんのKotlin(Java)コード上でConstraintLayoutの制約を編集するって記事がわかりやすく解説してくれてるよ。
あとは公式ドキュメント読んだら完璧。

5.右から左に移動する

これは多分色々やり方あるんだろうけど、今回はObjectAnimatorを使うよ。

移動する範囲は 画面幅 + TextViewの幅で求められるので、doOnLayoutを使ってレイアウトが決定したタイミングでアニメーションの設定をしてる。
これもうちょいいい感じにできそうだけどね。

textView.doOnLayout {
    val textViewWidth = it.width.toFloat()
    val objectAnimator = ObjectAnimator.ofFloat(
        textView,
        "translationX",
        0f,
        -(windowSize.width + textViewWidth)
    ).apply {
        interpolator = LinearInterpolator()
        duration = 3000L
    }.also {
        it.doOnEnd {
            // アニメーションが終わったViewを削除
            constraintLayout.removeView(textView)
        }
    }
    objectAnimator.start()
}

interpolatorはデフォルトのが気に入らなかったから、等速で移動するLinearInterpolatorに変更。

アニメーションが終わったらdoOnEndでremoveするのを忘れずに。
やらないとボタン押せば押すほどViewが溜まって、無限にアプリが重くなっていくよ。

ここまでやったらあとはボタンにクリックイベントつけて完成〜。

最後に

こういうの、意外と頑張ればなんとかなるものね。
また凝ったアニメーション挑戦したいなと思った。

一応ここでサンプル公開してるから、「わかんねえよ!!」ってなったら見てね。

おわり!

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What is going on with this article?