基本画面
- FrameLayoutをmatch/matchで設定しています。
- 円のカスタムビューをvisible=GONEで設定しています。
- 星のImageViewを2種類おいています。
- 星をクリックすると、円が拡大描画されていきます。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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"
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/back_color"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<com.kiyota.scaleanimationapp.CircleCustomView
android:id="@+id/main_circle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"></com.kiyota.scaleanimationapp.CircleCustomView>
<ImageView
android:id="@+id/star_pink"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:src="@drawable/ic_star_pink"></ImageView>
<ImageView
android:id="@+id/star_blue"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="100dp"
android:src="@drawable/ic_star"></ImageView>
</FrameLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
CircleCustomView.kt
class CircleCustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
/**
* サークルの色
*/
private val paint = Paint()
/**
* サークルの座標位置
*/
private val rect = RectF()
/**
* サークルの円周の長さ
*/
private var angle = 360F
/**
* 中心座標(x)
*/
private var x: Int = 0
/**
* 中心座標(y)
*/
private var y: Int = 0
/**
* 初回フラグ
*/
var isInit = true
/**
* コンパニオンオブジェクト
*/
companion object {
/**
* サークルの開始位置
*/
private const val angleTarget = 0F
}
/**
* コンストラクタ
*/
init {
// サークルの幅
this.paint.isAntiAlias = true
this.paint.style = Paint.Style.FILL_AND_STROKE
// サークルの色
this.paint.color = (context.resources.getColor(R.color.star_color))
}
/**
* ビュー描画メソッド
*
* @param canvas 描画領域
*/
@SuppressLint("CanvasSize")
public override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 初回は中心スタート
if (isInit) {
// サークル開始地点(中央揃え)
this.x = canvas.width / 2
this.y = canvas.height / 2
isInit = false
}
// サークルの背景色(透明)
canvas.drawColor(this.context.resources.getColor(R.color.color_back_circle))
// サークルの半径()大きさ
var radius = 40
val left = this.x - radius
val top = this.y - radius
val right = this.x + radius
val bottom = this.y + radius
// サークルの領域設定
this.rect.set(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
// サークルの描画
canvas.drawArc(this.rect, angleTarget, this.angle, false, this.paint)
}
/**
* 中心座標変更メソッド
*/
fun changeCenter(x: Int, y: Int) {
// サークルの中心座標
this.x = x
this.y = y
}
/**
* サークル色変更メソッド
*
* @param index 押されたボタンの番号
*/
fun changeColor(index: Int) {
when (index) {
0 -> {
this.paint.color = context.resources.getColor(R.color.colorAccent)
}
1 -> {
this.paint.color = context.resources.getColor(R.color.star_color)
}
else -> {
this.paint.color = context.resources.getColor(R.color.colorPrimary)
}
}
}
}
画面の中心で円を拡大する場合(ピンク)
- 中心座標(540 , 792)
- pivot(0.5f , 0.5f)
MainActivity.kt
package com.kiyota.scaleanimationapp
class MainActivity : AppCompatActivity(), Animation.AnimationListener {
private var index = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// クリックされたらアニメーションをスタートする
star_pink.setOnClickListener {
index = 0
// 端末(Nexus5x)の中心座標が(540,792)という意味です
startScalingXml(540, 792, index)
}
star_blue.setOnClickListener {
index = 1
startScalingXml(540, 792, index)
}
}
/**
* サークル拡大アニメーションメソッド
*
* @param x x座標
* @param y y座標
* @param index クリックされたビューの順番
*/
private fun startScalingXml(x: Int, y: Int, index: Int) {
main_circle.changeCenter(x, y)
main_circle.changeColor(index)
var scaleAnimation = ScaleAnimation(
1.0f, 30.0f, 1.0f, 30.0f,
Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f
)
scaleAnimation.duration = 20000
scaleAnimation.repeatCount = 0
scaleAnimation.fillAfter = true
main_circle.visibility = VISIBLE
scaleAnimation.setAnimationListener(this)
main_circle.startAnimation(scaleAnimation)
}
override fun onAnimationRepeat(p0: Animation?) {
}
/**
* アニメーション終了時処理メソッド
*
* @param p0 アニメーション
*/
override fun onAnimationEnd(p0: Animation?) {
setColorByIndex(index)
main_circle.visibility = GONE
}
override fun onAnimationStart(p0: Animation?) {
}
/**
* 背景色切り替えメソッド
*
* @param index クリックされたビューの順番
*/
private fun setColorByIndex(index: Int) {
when (index) {
0 -> {
back_color.setBackgroundColor(this.resources.getColor(R.color.colorAccent))
}
1 -> {
back_color.setBackgroundColor(this.resources.getColor(R.color.star_color))
}
else -> {
back_color.setBackgroundColor(this.resources.getColor(R.color.colorPrimary))
}
}
}
}
画面の左側で円を拡大する場合(水色) :失敗
- 中心座標(270 , 792)
- pivot(0.5f , 0.5f)
画面の左側で円を拡大する場合(水色) :成功
- 中心座標(270 , 792)
- pivot(0.25f , 0.5f)
※x軸の値を半分にしてあげればOK