上一篇文章介绍了属性动画以及如何自定义属性动画,如果关于自定义属性动画你还存在疑问请回去查看上一篇:Android属性动画。
那么接下来我们就介绍如果通过自定义属性来实现3D翻转动画效果,首先看效果,效果有点low,大家不要吐槽,主要是要掌握其中的精髓。效果如下:
首先上代码:
class ThreeDRotateView : ViewGroup {
private val mCamera = Camera()
private val mMatrix = Matrix()
private var changeAngle = 0F
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
measureChildren(widthMeasureSpec, heightMeasureSpec)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
for (i in 0 until childCount) {
val child = getChildAt(i)
child.layout(
0, 0,
child.measuredWidth,
child.measuredHeight
)
}
}
override fun dispatchDraw(canvas: Canvas?) {
for (i in 0 until childCount) {
drawScreen(canvas, i, drawingTime)
}
}
private fun drawScreen(canvas: Canvas?, i: Int, drawingTime: Long) {
val centerX = (width / 2).toFloat()
val centerY = height.toFloat() / 2
if (canvas != null) {
if (changeAngle >= 90F && i == 1) {
} else {
drawView(canvas, i, centerX, centerY, drawingTime)
}
}
}
private fun drawView(canvas: Canvas, i: Int, centerX: Float, centerY: Float, drawingTime: Long) {
canvas.save()
mCamera.save()
mCamera.rotateY(180F * (i + 1) + changeAngle)
mCamera.getMatrix(mMatrix)
mCamera.restore()
mMatrix.preTranslate(-centerX, -centerY)
mMatrix.postTranslate(centerX, centerY)
canvas.concat(mMatrix)
val view = getChildAt(i)
drawChild(canvas, view, drawingTime)
canvas.restore()
}
fun setChangeAngle(changeAngle: Float) {
this.changeAngle = changeAngle
invalidate()
}
fun getChangeAngle(): Float {
return changeAngle
}
}
布局代码如下:
<com.enhance.kmf.democustomview.view.ThreeDRotateView
android:layout_width="match_parent"
android:id="@+id/tdrvContent"
android:layout_marginTop="50dp"
android:layout_height="wrap_content">
<RelativeLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_ff5283cc">
<ImageView android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:background="@drawable/vector_play"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android 自定义属性实现3D翻转动效"
android:textSize="28sp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="170dp"
android:layout_centerInParent="true"
android:textColor="@color/color_ffffffff"/>
</RelativeLayout>
<RelativeLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_ff119caa"
>
<ImageView android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:background="@drawable/vector_pause"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" Android 自定义属性实现3D翻转动效"
android:textSize="28sp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="170dp"
android:layout_centerInParent="true"
android:textColor="@color/color_ffffffff"
/>
</RelativeLayout>
</com.enhance.kmf.democustomview.view.ThreeDRotateView>
调用代码如下:
ObjectAnimator.ofFloat(具体控件, "changeAngle", 0F, 180F).apply {
duration = 1000
start()
}
看过上一篇文章的读者应该会对这个套路比较熟悉,还是那三点
- 首先我们需要根据需求自定义出相应的动画属性;
- 给我们的属性设置相应的get()和set()注意set()方法需要调用invalidate(),
- 我们就按照平常的属性动画就能操作自定义的动画了。
只不过这次是重写的ViewGroup,通过角度判断看是否需要绘制区域来达到动画翻转的效果,角度不够的时候就不绘制该区域的view,只有达到条件才绘制相关view。
具体思路就是通过重写ViewGroup的dispatchDraw()方法,对子view的绘制过程进行控制,然后调用Camera的rotateY()对角度进行控制,以达到翻转的效果。