LoginSignup
0
3

More than 3 years have passed since last update.

Fragment内のCanvasで図形をアニメーションさせる

Last updated at Posted at 2019-09-13

はじめに

他の画面には全く使わないけど1画面だけパーティクルとか出したいみたいな需要が発生してそこのためにUnityとかを使ったらいけないかなぁ…と思ったのでこれを下地に作っていけないかなというやつです

テンプレートはEmptyActivityを選択した状態から開発していきます

Fragment用のレイアウトファイルを作る

Fragmentで使うレイアウトファイルを用意します。下記のようにシンプルなものを使います

fragment_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/anim_fragment_body"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
</LinearLayout>

Fragmentを作成する

一旦Activityで読み込むようにしたいのでシンプルなFragmentを作成します

AnimFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class AnimFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_anim, container, false)
    }
}

MainActivity用のレイアウトファイルにFragmentを配置

表示確認したいのでFragmentを配置します。
activity_main.xmlを下記のように書き換えます。

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:baselineAligned="false">

    <fragment
        android:id="@+id/fragment"
        android:name="io.github.tamfoi.fragmentcanvas.AnimFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />
</LinearLayout>

CustomView(Canvas)を作成してFragmentに表示

下記のようにFragmentを修正します。

やった作業

  • CustomViewの作成
  • CustomViewをFragmentのViewに追加
  • CustomViewに四角を表示する
AnimFragment.kt
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment

class AnimFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        val view = inflater.inflate(R.layout.fragment_anim, container, false)
        val layout = view.findViewById<LinearLayout>(R.id.anim_fragment_body)
        layout.addView(AnimView(this.activity))

        return view
    }

    class AnimView : View {
        constructor(context: Context?) : super(context)
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
        constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)

            val paint = Paint()
            paint.color = Color.BLACK
            val rect = Rect(100, 200, 300, 400)
            canvas!!.drawRect(rect, paint)

        }
    }
}

下記のようにCanvas内に四角が出れば成功です。
fragmentcancas1.PNG

Animationするためのループを作る

下記のように編集してHandlerを使ってループ処理を作ります

AnimFragment.kt
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.os.Bundle
import android.os.Handler
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment

class AnimFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        val view = inflater.inflate(R.layout.fragment_anim, container, false)
        val layout = view.findViewById<LinearLayout>(R.id.anim_fragment_body)
        val animView = AnimView(this.activity)
        layout.addView(animView)

        val handler = Handler()
        handler.post(object : Runnable{
            override fun run() {
                animView.invalidate();
                handler.postDelayed(this, 16);
            }
        })

        return view
    }

    class AnimView : View {
        constructor(context: Context?) : super(context)
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
        constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)

            val paint = Paint()
            paint.color = Color.BLACK
            val rect = Rect(100, 200, 300, 400)
            canvas!!.drawRect(rect, paint)

        }
    }
}

Animationさせてみる

onDrawを下記のように編集してみます

AnimFragment.kt
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.os.Bundle
import android.os.Handler
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import kotlin.math.roundToInt
import kotlin.math.sin

class AnimFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        val view = inflater.inflate(R.layout.fragment_anim, container, false)
        val layout = view.findViewById<LinearLayout>(R.id.anim_fragment_body)
        val animView = AnimView(this.activity)
        layout.addView(animView)

        val handler = Handler()
        handler.post(object : Runnable{
            override fun run() {
                animView.invalidate();
                handler.postDelayed(this, 16);
            }
        })

        return view
    }

    class AnimView : View {

        constructor(context: Context?) : super(context)
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
        constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)

            val paint = Paint()
            paint.color = Color.BLACK
            val rect = Rect(400, 600, 700, 900)

            val offsetY = sin(System.currentTimeMillis().toDouble() * 0.005) * 500
            rect.offset(0, offsetY.roundToInt())

            canvas!!.drawRect(rect, paint)

        }
    }
}

下記のようになりました(sinの動き楽しいですね)

fragmentcanvas2.gif

おわりに

実際のところパフォーマンス的にどうなのか分からないのでこうしたほうが良いよみたいなのあったら知りたいです

参考

http://muumuutech.hatenablog.com/entry/2017/10/29/163705
https://stackoverflow.com/questions/23280685/drawing-in-a-fragment-in-android/23282354#23282354
http://blog.livedoor.jp/stock_club/archives/52105545.html
https://tech.recruit-mp.co.jp/mobile/remember_canvas1/
https://sites.google.com/a/asabon.net/asabon_site/android_programming/coding/ondraw
https://qiita.com/aftercider/items/81edf35993c2df3de353

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3