效果图
关键方法解释
Animation.initialize (width: Int, height: Int, parentWidth: Int, parentHeight: Int)
函数会在执行动画前调用 参数中的width height 表示将要执行动画的view的宽高 parentwidth parentheight 表示执行动画view父控件
的宽高 一般在该函数完成初始化操作
Animation.applyTransformation (interpolatedTime: Float, t: Transformation?)
用来自定义Animation的函数
interpolatedTime 动画进度 0-1
t 当前进度下 需要对控件应用变换的操作都保存在Transformation 中
Camera.save() Camera.restore()
和Canvas类似 都是用来保存和回滚操作
Camera.getMatrix(matrix)
// 获取camera的 Matrix 赋值给传参对象
// 改变选中的中心点
matrix.preTranslate(-mCenterx , -mCentery)
matrix.postTranslate(mCenterx , mCentery)
activity代码 翻转1
package com.bhb.seniorcustomview.camera
import android.graphics.Camera
import android.graphics.Matrix
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.animation.Animation
import android.view.animation.Transformation
import com.bhb.seniorcustomview.R
import kotlinx.android.synthetic.main.activity_rotatte3d.*
class Rotatte3dActivity : AppCompatActivity() {
// 动画时长
var duration = 2000L
// 正旋转动画
lateinit var openAnimation : Rotate3dAnimation
// 反旋转动画
lateinit var closeAnimation : Rotate3dAnimation
var isOpen = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_rotatte3d)
initOpenAnim()
initCloseAnim()
btn_open.setOnClickListener {
if(openAnimation.hasStarted() && !openAnimation.hasEnded()){
return@setOnClickListener
}
if(closeAnimation.hasStarted() && !closeAnimation.hasEnded()){
return@setOnClickListener
}
if(isOpen){
ll_content.startAnimation(closeAnimation)
}else{
ll_content.startAnimation(openAnimation)
}
isOpen = !isOpen
}
}
// 初始化动画
fun initOpenAnim(){
openAnimation = Rotate3dAnimation(0f,180f)
openAnimation.duration = duration
// 动画结束时保留当前的状态
openAnimation.fillAfter = true
}
fun initCloseAnim(){
closeAnimation = Rotate3dAnimation(180f , 0f)
closeAnimation.duration = duration
closeAnimation.fillAfter = true
}
}
// 旋转动画
class Rotate3dAnimation : Animation{
final val mFromDegress : Float
final val mEndDegress : Float
var mCenterx = 0f
var mCentery = 0f
lateinit var mCamera : Camera
constructor(fromDegress : Float , endDegress : Float){
mFromDegress = fromDegress
mEndDegress = endDegress
}
override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) {
super.initialize(width, height, parentWidth, parentHeight)
// 在这里执行初始化操作
mCenterx = width/2f
mCentery = height/2f
mCamera = Camera()
}
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
//执行自定义动画操作
// 计算当前进度的旋转角度
var degress = mFromDegress + ((mEndDegress - mFromDegress) * interpolatedTime)
mCamera.save()
val matrix = t!!.matrix
mCamera.rotateY(degress)
mCamera.getMatrix(matrix)
mCamera.restore()
// 改变旋转的中心点
matrix.preTranslate(-mCenterx , -mCentery)
matrix.postTranslate(mCenterx , mCentery)
super.applyTransformation(interpolatedTime, t)
}
}
布局文件
<?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"
android:orientation="vertical"
android:gravity="top|center_horizontal"
tools:context=".camera.Rotatte3dActivity">
<Button
android:id="@+id/btn_open"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="翻转"
android:textSize="16sp"/>
<LinearLayout
android:id="@+id/ll_content"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:layout_width="300dp"
android:layout_height="300dp"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_logo"
android:src="@mipmap/animal1"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</LinearLayout>
activity代码 翻转2
翻转1中 实现了翻转的效果 但是在翻转过程中感觉图片会先变大后变小 翻转到90度时最大
这里我们要加入z轴的旋转 z轴越大 图片越小 z轴越小图片越大
所以 在旋转动画不断接近90度的过程中我们要渐渐扩大z轴的旋转
这里把 整个0-180 度的动画 拆分成两个 0-90 z轴变大 90-180z轴变小
关键代码
var z = 0f
if(mReserver){
z = mDepthz * interpolatedTime
mCamera.translate(0f,0f,z)
}else{
z = mDepthz * (1-interpolatedTime)
mCamera.translate(0f ,0f ,z)
}
package com.bhb.seniorcustomview.camera
import android.graphics.Camera
import android.graphics.Matrix
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.animation.AccelerateInterpolator
import android.view.animation.Animation
import android.view.animation.Transformation
import com.bhb.seniorcustomview.R
import kotlinx.android.synthetic.main.activity_rotatte3d.*
class Rotatte3dActivity2 : AppCompatActivity() {
var duration = 2000L
lateinit var openAnimation : Rotate3dAnimation2
lateinit var closeAnimation : Rotate3dAnimation2
var isOpen = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_rotatte3d2)
initOpenAnim()
initCloseAnim()
btn_open.setOnClickListener {
if(openAnimation.hasStarted() && !openAnimation.hasEnded()){
return@setOnClickListener
}
if(closeAnimation.hasStarted() && !closeAnimation.hasEnded()){
return@setOnClickListener
}
if(isOpen){
ll_content.startAnimation(closeAnimation)
}else{
ll_content.startAnimation(openAnimation)
}
isOpen = !isOpen
}
}
fun initOpenAnim(){
openAnimation = Rotate3dAnimation2(0f,90f , true)
openAnimation.duration = duration
openAnimation.fillAfter = true
openAnimation.setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
var rotateAnimation = Rotate3dAnimation2(90f,180f,false)
rotateAnimation.duration = duration
rotateAnimation.fillAfter = true
ll_content.startAnimation(rotateAnimation)
}
override fun onAnimationStart(animation: Animation?) {
}
})
}
fun initCloseAnim(){
closeAnimation = Rotate3dAnimation2(180f , 90f , true)
closeAnimation.duration = duration
closeAnimation.fillAfter = true
closeAnimation.setAnimationListener(object :Animation.AnimationListener{
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
var rotateAnimation = Rotate3dAnimation2(90f,0f,false)
rotateAnimation.duration = duration
rotateAnimation.fillAfter = true
ll_content.startAnimation(rotateAnimation)
}
override fun onAnimationStart(animation: Animation?) {
}
})
}
}
class Rotate3dAnimation2 : Animation{
final val mFromDegress : Float
final val mEndDegress : Float
var mDepthz = 400
var mReserver : Boolean
var mCenterx = 0f
var mCentery = 0f
lateinit var mCamera : Camera
constructor(fromDegress : Float , endDegress : Float , reserver:Boolean){
mFromDegress = fromDegress
mEndDegress = endDegress
mReserver = reserver
}
override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) {
super.initialize(width, height, parentWidth, parentHeight)
// 在这里执行初始化操作
mCenterx = width/2f
mCentery = height/2f
mCamera = Camera()
}
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
//执行自定义动画操作
var degress = mFromDegress + ((mEndDegress - mFromDegress) * interpolatedTime)
mCamera.save()
var z = 0f
if(mReserver){
z = mDepthz * interpolatedTime
mCamera.translate(0f,0f,z)
}else{
z = mDepthz * (1-interpolatedTime)
mCamera.translate(0f ,0f ,z)
}
val matrix = t!!.matrix
mCamera.rotateY(degress)
mCamera.getMatrix(matrix)
mCamera.restore()
matrix.preTranslate(-mCenterx , -mCentery)
matrix.postTranslate(mCenterx , mCentery)
super.applyTransformation(interpolatedTime, t)
}
}
activity代码 翻转3
这里我们加上旋转过程中切换图片
通过监听动画结束 设置不同的图片资源
关键代码
import android.graphics.Camera
import android.graphics.Matrix
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.animation.AccelerateInterpolator
import android.view.animation.Animation
import android.view.animation.Transformation
import com.bhb.seniorcustomview.R
import kotlinx.android.synthetic.main.activity_rotatte3d.*
import kotlinx.android.synthetic.main.activity_rotatte3d.btn_open
import kotlinx.android.synthetic.main.activity_rotatte3d.iv_logo
import kotlinx.android.synthetic.main.activity_rotatte3d.ll_content
import kotlinx.android.synthetic.main.activity_rotatte3d3.*
class Rotatte3dActivity3 : AppCompatActivity() {
var duration = 2000L
lateinit var openAnimation : Rotate3dAnimation3
lateinit var closeAnimation : Rotate3dAnimation3
var isOpen = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_rotatte3d3)
initOpenAnim()
initCloseAnim()
btn_open.setOnClickListener {
if(openAnimation.hasStarted() && !openAnimation.hasEnded()){
return@setOnClickListener
}
if(closeAnimation.hasStarted() && !closeAnimation.hasEnded()){
return@setOnClickListener
}
if(isOpen){
iv_logo.setImageResource(R.mipmap.animal2)
ll_content.startAnimation(closeAnimation)
}else{
iv_logo.setImageResource(R.mipmap.animal1)
ll_content.startAnimation(openAnimation)
}
isOpen = !isOpen
}
}
fun initOpenAnim(){
openAnimation = Rotate3dAnimation3(0f,90f , true)
openAnimation.duration = duration
openAnimation.fillAfter = true
openAnimation.setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
iv_logo.setImageResource(R.mipmap.animal2)
var rotateAnimation = Rotate3dAnimation3(90f,180f,false)
rotateAnimation.duration = duration
rotateAnimation.fillAfter = true
ll_content.startAnimation(rotateAnimation)
}
override fun onAnimationStart(animation: Animation?) {
}
})
}
fun initCloseAnim(){
closeAnimation = Rotate3dAnimation3(180f , 90f , true)
closeAnimation.duration = duration
closeAnimation.fillAfter = true
closeAnimation.setAnimationListener(object :Animation.AnimationListener{
override fun onAnimationRepeat(animation: Animation?) {
}
override fun onAnimationEnd(animation: Animation?) {
iv_logo.setImageResource(R.mipmap.animal1)
var rotateAnimation = Rotate3dAnimation3(90f,0f,false)
rotateAnimation.duration = duration
rotateAnimation.fillAfter = true
ll_content.startAnimation(rotateAnimation)
}
override fun onAnimationStart(animation: Animation?) {
}
})
}
}
class Rotate3dAnimation3 : Animation{
final val mFromDegress : Float
final val mEndDegress : Float
var mDepthz = 400
var mReserver : Boolean
var mCenterx = 0f
var mCentery = 0f
lateinit var mCamera : Camera
constructor(fromDegress : Float , endDegress : Float , reserver:Boolean){
mFromDegress = fromDegress
mEndDegress = endDegress
mReserver = reserver
}
override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) {
super.initialize(width, height, parentWidth, parentHeight)
// 在这里执行初始化操作
mCenterx = width/2f
mCentery = height/2f
mCamera = Camera()
}
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
//执行自定义动画操作
var degress = mFromDegress + ((mEndDegress - mFromDegress) * interpolatedTime)
mCamera.save()
var z = 0f
if(mReserver){
z = mDepthz * interpolatedTime
mCamera.translate(0f,0f,z)
}else{
z = mDepthz * (1-interpolatedTime)
mCamera.translate(0f ,0f ,z)
}
val matrix = t!!.matrix
mCamera.rotateY(degress)
mCamera.getMatrix(matrix)
mCamera.restore()
matrix.preTranslate(-mCenterx , -mCentery)
matrix.postTranslate(mCenterx , mCentery)
super.applyTransformation(interpolatedTime, t)
}
}