效果图
布局文件内容如下
<?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=".ui.home.HomeFragment">
<TextView
android:id="@+id/text_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top_show"
android:layout_width="335dp"
android:layout_height="267dp"
android:background="@android:color/holo_blue_dark"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tv_top_show"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@android:color/holo_green_dark"
android:gravity="center"
android:text="上"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_bottom_show"
android:layout_width="335dp"
android:layout_height="209dp"
android:layout_marginTop="8dp"
android:background="@android:color/holo_red_dark"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/cl_top_show">
<TextView
android:id="@+id/tv_bottom_show"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@android:color/holo_green_dark"
android:gravity="center"
android:text="下"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_top_anim"
android:layout_width="335dp"
android:layout_height="267dp"
android:background="@android:color/holo_blue_dark"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="@+id/cl_top_show"
app:layout_constraintRight_toRightOf="@+id/cl_top_show"
app:layout_constraintTop_toTopOf="@+id/cl_top_show">
<TextView
android:id="@+id/tv_top_anim"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@android:color/holo_green_dark"
android:gravity="center"
android:text="上"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_bottom_anim"
android:layout_width="335dp"
android:layout_height="209dp"
android:background="@android:color/holo_red_dark"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="@+id/cl_bottom_show"
app:layout_constraintRight_toRightOf="@+id/cl_bottom_show"
app:layout_constraintTop_toTopOf="@+id/cl_bottom_show">
<TextView
android:id="@+id/tv_bottom_anim"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@android:color/holo_green_dark"
android:gravity="center"
android:text="下"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Activity部分代码内容如下
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.tvBottomShow.text = "${nowNumber}下"
binding.tvTopShow.text = "${nowNumber}上"
binding.tvTopAnim.text = "${nowNumber}上"
binding.tvBottomAnim.text = "${nowNumber}下"
binding.clBottomShow.setOnTouchListener(object : View.OnTouchListener {
var startY = 0f
override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
var returnValue = false
when (p1?.action) {
MotionEvent.ACTION_DOWN -> {
startY = p1.y
}
MotionEvent.ACTION_UP -> {
if ((p1.y - startY) < -20) {
nowNumber += 1
binding.tvBottomShow.text = "${nowNumber}下"
clickTop()
returnValue = true
}
}
}
Log.e("TAG", "onTouch: ${p1?.y}------$returnValue------${p1?.action}")
return returnValue
}
})
binding.clBottomShow.setOnClickListener {
Log.e("TAG", "onViewCreated: cl")
}
binding.tvBottomShow.setOnClickListener {
Log.e("TAG", "onViewCreated: ")
Toast.makeText(context, "bottom", Toast.LENGTH_SHORT).show()
}
binding.clTopShow.setOnTouchListener(object : View.OnTouchListener {
var startY = 0f
override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
var returnValue = false
when (p1?.action) {
MotionEvent.ACTION_DOWN -> {
startY = p1.y
}
MotionEvent.ACTION_UP -> {
if ((p1.y - startY) > 20) {
nowNumber -= 1
binding.tvTopShow.text = "${nowNumber}上"
clickBottom()
returnValue = true
}
}
}
return returnValue
}
})
binding.clTopShow.setOnClickListener {
Log.e("TAG", "onViewCreated: cl")
}
binding.tvTopShow.setOnClickListener {
Toast.makeText(context, "top", Toast.LENGTH_SHORT).show()
}
}
/**
* 点击顶部实现动画
*/
private fun clickTop() {
val rotationY2 = RotationYAnimation()
rotationY2.apply {
index = 1
duration = 150
setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationStart(p0: Animation?) {}
override fun onAnimationEnd(p0: Animation?) {
binding.clTopAnim.visibility = View.GONE
binding.clBottomAnim.visibility = View.GONE
binding.tvTopShow.text = "${nowNumber}上"
binding.tvTopAnim.text = "${nowNumber}上"
binding.tvBottomAnim.text = "${nowNumber}下"
}
override fun onAnimationRepeat(p0: Animation?) {}
})
}
val rotationY1 = RotationYAnimation()
rotationY1.apply {
index = 0
duration = 200
setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationStart(p0: Animation?) {}
override fun onAnimationEnd(p0: Animation?) {
binding.clTopAnim.apply {
startAnimation(rotationY2)
binding.clBottomAnim.visibility = View.GONE
visibility = View.VISIBLE
}
}
override fun onAnimationRepeat(p0: Animation?) {}
})
}
binding.clTopAnim.visibility = View.INVISIBLE
binding.clBottomAnim.visibility = View.VISIBLE
binding.clBottomAnim.startAnimation(rotationY1)
}
/**
* 点击底部实现动画
*/
private fun clickBottom() {
val rotationY3 = RotationYAnimation()
rotationY3.apply {
index = 0
direction = 1
duration = 150
setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationStart(p0: Animation?) {}
override fun onAnimationEnd(p0: Animation?) {
binding.clTopAnim.visibility = View.GONE
binding.clBottomAnim.visibility = View.GONE
binding.tvBottomShow.text = "${nowNumber}下"
binding.tvTopAnim.text = "${nowNumber}上"
binding.tvBottomAnim.text = "${nowNumber}下"
}
override fun onAnimationRepeat(p0: Animation?) {}
})
}
val rotationY4 = RotationYAnimation()
rotationY4.apply {
index = 1
direction = 1
duration = 200
setAnimationListener(object : Animation.AnimationListener{
override fun onAnimationStart(p0: Animation?) {}
override fun onAnimationEnd(p0: Animation?) {
binding.clBottomAnim.apply {
startAnimation(rotationY3)
binding.clTopAnim.visibility = View.INVISIBLE
visibility = View.VISIBLE
}
}
override fun onAnimationRepeat(p0: Animation?) {}
})
}
binding.clBottomAnim.visibility = View.INVISIBLE
binding.clTopAnim.visibility = View.VISIBLE
binding.clTopAnim.startAnimation(rotationY4)
}
工具类内容如下
class RotationYAnimation : Animation() {
private var centerX = 0
private var centerY: Int = 0
private val camera: Camera = Camera()
// 第几个view 0:第二个 1:第一个
var index = 0
// 方向 0:向上 1:向下
var direction = 0
/**
* 获取坐标,定义动画时间
*/
override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) {
super.initialize(width, height, parentWidth, parentHeight)
//获得中心点坐标
centerX = width / 2
centerY = if (index == 0) {
0
} else {
height
}
}
/**
* 旋转的角度设置
*/
override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
val matrix: Matrix = t.matrix
camera.save()
//设置camera的位置
camera.setLocation(0F, 0F, -90F)
//中心是Y轴旋转,这里可以自行设置X轴 Y轴 Z轴
// camera.rotateX(360 * interpolatedTime)
camera.rotateX(
if (direction == 0) {
if (index == 0) {
90 * interpolatedTime
} else {
(90 * interpolatedTime) + 270
}
} else {
if (index == 0) {
(-90 * interpolatedTime) + 90
} else {
-90 * interpolatedTime
}
}
)
//把我们的摄像头加在变换矩阵上
camera.getMatrix(matrix)
//设置翻转中心点
matrix.preTranslate((-centerX).toFloat(), (-centerY).toFloat())
matrix.postTranslate(centerX.toFloat(), centerY.toFloat())
camera.restore()
}
}