自定义动画的实现-实例

一:效果

上面是一个大嘴在吃一个球,下面是三个球分别一大一小的变化

         

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()


}
}



posted @ 2021-05-16 17:26  哎睡的懒洋洋  阅读(153)  评论(0编辑  收藏  举报