画面をタッチしたときのフィードバックに、自分で用意した画像をフェードアウトするアニメーションで実装する方法を説明します。
動作イメージ
タッチした座標にフィードバック用の画像を300ミリ秒かけてフェードアウトさせています。
ソースコード
タッチのフィードバック用に作成したTouchFeedbackViewを上に重ねて、タッチした座標にフィードバック用の画像を描画&フェードアウトするアニメーションをtouchFeedbackメソッドで実行しています。
開発中のマインスイーパーのソースから関連する部分を抜粋して載せておきます。
開発環境は次の通りです。
PC | MacBook Pro(2016年モデル) |
IDE | Android Studio 4.0.1 |
Android SDK | minSdkVersion 21 targetSdkVersion 30 |
言語 | Kotlin 1.3.72 |
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.sosotata.minesweeper.ui.widgets.SquareTileGameView
android:id="@+id/squareView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.sosotata.minesweeper.ui.widgets.TouchFeedbackView
android:id="@+id/touchAnimationView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
package com.sosotata.minesweeper.ui.main
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.sosotata.minesweeper.R
import kotlinx.android.synthetic.main.game_fragment.*
class GameFragment : Fragment(), View.OnTouchListener {
companion object {
fun newInstance() = GameFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.game_fragment, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
squareView.setOnTouchListener(this)
}
override fun onTouch(vw: View?, e: MotionEvent?): Boolean {
if (e?.action == MotionEvent.ACTION_UP) {
// タッチのフィードバック実行!!
touchAnimationView.touchFeedback(e.x, e.y)
}
return squareView.onTouchEvent(e)
}
}
package com.sosotata.minesweeper.ui.widgets
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.PointF
import android.util.AttributeSet
import android.view.View
import android.view.animation.AlphaAnimation
import com.sosotata.minesweeper.R
/**
* タッチアニメーションビュー
*/
class TouchFeedbackView: View {
/** タッチアニメーション用画像 **/
private val mTouchImage: Bitmap
/** タッチ座標 **/
private val mTouchPos = PointF()
/**
* コンストラクタ
*/
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
mTouchImage = BitmapFactory.decodeResource(context.resources, R.drawable.touch_image)
}
/**
* [android.view.View.onDraw]
*/
override fun onDraw(canvas: Canvas) {
if (mTouchPos.x >= 0 && mTouchPos.y >= 0) {
canvas.drawBitmap(
mTouchImage,
mTouchPos.x - (mTouchImage.width / 2f),
mTouchPos.y - (mTouchImage.height / 2f),
null
)
}
super.onDraw(canvas)
}
/**
* タッチフィードバック実行
*/
fun touchFeedback(x: Float, y: Float) {
mTouchPos.x = x
mTouchPos.y = y
val fadeOut = AlphaAnimation(1.0f, 0.0f)
fadeOut.duration = 300
fadeOut.fillAfter = true
startAnimation(fadeOut)
}
}
コメント