一:效果
上面是一个大嘴在吃一个球,下面是三个球分别一大一小的变化
GitHub地址:https://github.com/luofangli/Custom_Animation
代码:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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"> <com.example.custom_animation.BigEatSmallCircle android:id="@+id/myview" android:layout_width="0dp" android:layout_height="200dp" android:layout_marginStart="10dp" android:layout_marginTop="10dp" android:layout_marginEnd="10dp" android:background="@color/design_default_color_primary" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <com.example.custom_animation.CircleFollowJump android:id="@+id/circleAnima" android:layout_width="0dp" android:layout_height="200dp" android:layout_marginStart="10dp" android:layout_marginEnd="10dp" android:background="@color/black" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/myview" /> </androidx.constraintlayout.widget.ConstraintLayout>
package com.example.custom_animation import android.animation.ValueAnimator import android.animation.ValueAnimator.INFINITE import android.animation.ValueAnimator.ofFloat import android.content.Context import android.graphics.* import android.util.AttributeSet import android.util.Log import android.view.View import androidx.core.graphics.toRectF class BigEatSmallCircle:View { //小圆的半径 private var smallArcRadius = 0f //大圆的动画因子 private var sweepAngle = 0f private var startAngle = 0f //小圆的x,y坐标 private var smallCircleX = 0f private var smallCircleY = 0f //小圆x的最大距离 private var smallCircleBigX = 0f //大圆的动画 private var valueAnimatorBigArc = ValueAnimator() //小圆的动画 private var valueAnimatorSmallCircle = ValueAnimator() //画大圆的paint private val paintBigCircle: Paint by lazy { Paint().apply { style = Paint.Style.FILL color = Color.RED } } constructor(context: Context):super(context){} constructor(context: Context,attributeSet: AttributeSet):super(context,attributeSet){} override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) Log.v("lfl","在OnSizeChanged") ArcRect() } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) //画大圆 canvas?.drawArc(ArcRect(),startAngle,sweepAngle,true,paintBigCircle) //画小圆 canvas?.drawCircle(smallCircleX,smallCircleY,smallArcRadius,paintBigCircle) } //确定圆弧的矩形区域 并且确定小圆的x,y坐标 private fun ArcRect():RectF{ //距离画布左右边缘的距离为 var xDistance = 0f //距离画布上下边缘的距离 var yDistance = 0f //当画布的高度小于宽度时 if (measuredHeight<measuredWidth){ smallArcRadius = measuredHeight/6f xDistance = (measuredWidth-8.5f*smallArcRadius)/2 }else{ smallArcRadius = measuredWidth/8.5f yDistance = (measuredHeight-6*smallArcRadius)/2 } //确定小圆的x,y坐标 smallCircleBigX = xDistance+7.5f*smallArcRadius smallCircleY = yDistance+3*smallArcRadius //返回大圆的矩形区域 return RectF(xDistance,yDistance, (xDistance+6*smallArcRadius).toFloat(), (yDistance+6*smallArcRadius).toFloat()) } //大圆的动画因子的改变 private fun changBigArcAngle(){ valueAnimatorBigArc = ValueAnimator.ofFloat(0f,45f).apply { duration = 1000L repeatCount = INFINITE addUpdateListener { val value = it.animatedValue as Float startAngle = value sweepAngle = 360f-value*2 invalidate() } } //小球移动的动画 valueAnimatorSmallCircle = ValueAnimator.ofFloat(0f,5.5f*87.5f).apply { duration = 1000L repeatCount = INFINITE addUpdateListener { val value = it.animatedValue as Float smallCircleX = smallCircleBigX - value invalidate() } } } //启动动画 fun startAnima(){ changBigArcAngle() valueAnimatorBigArc.start() valueAnimatorSmallCircle.start() } }
package com.example.custom_animation import android.animation.ValueAnimator import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.util.AttributeSet import android.util.Log import android.view.CollapsibleActionView import android.view.ContextMenu import android.view.View class CircleFollowJump:View { //圆的半径 private var raduis = 0f //圆在y轴上的位置 private var cy = 0f //圆的x的位置 private val cxArray = mutableListOf<Float>() //存圆的半径 private val raduisArray = arrayOf(0f,0f,0f) //存入动画 private val valueAnimatorArray = mutableListOf<ValueAnimator>() //准备画笔 private val paint_circle:Paint by lazy { Paint().apply { style = Paint.Style.FILL color = Color.RED } } constructor(context: Context):super(context){} constructor(context: Context,attributeSet: AttributeSet):super(context,attributeSet){} override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { super.onSizeChanged(w, h, oldw, oldh) sure_centerAndradius() } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) //画三个圆 draw3circle(canvas) } //确定中心点,以及圆的最大半径 private fun sure_centerAndradius(){ //临时判断值, val temp = measuredHeight/2f if (7*temp>measuredWidth){ //圆的半径大了, raduis = measuredWidth/7f }else{ //圆的半径刚刚好 raduis = temp } //在x轴上圆离两边的距离 val xDistance = (measuredWidth-7*raduis)/2 //在y轴上圆离两边的距离 val yDistance = (measuredHeight-2*raduis)/2 //圆中心点y cy = yDistance+raduis //将半径存入数组中 //各圆中心点x for (i in 0..2){ raduisArray[i] = raduis val cx = (xDistance+raduis+i*2.5*raduis).toFloat() cxArray.add(cx) } } //画三个圆 private fun draw3circle(canvas: Canvas?){ for (i in 0..2){ canvas?.drawCircle(cxArray[i],cy,raduisArray[i],paint_circle) } } //动画因子的改变 private fun changeRadius(){ Log.v("lfl","在改变因子方法中") for (i in 0..2){ ValueAnimator.ofFloat(1f,0.1f,1f).apply { duration = 1000 repeatCount = ValueAnimator.INFINITE startDelay = i*155L addUpdateListener { val value = it.animatedValue as Float //各圆半径为 raduisArray[i] = raduis*value invalidate() } valueAnimatorArray.add(this) } } } //启动动画 fun startAnima(){ changeRadius() for (i in 0..2){ valueAnimatorArray[i].start() } } }
package com.example.custom_animation import android.animation.ValueAnimator import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) myview.startAnima() circleAnima.startAnima() } }