2025-11-25

import android.os.Bundle

import android.view.animation.*

import android.widget.ImageView

import android.widget.RadioGroup

import android.widget.Switch

import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    private lateinit var ivRotating: ImageView

    private lateinit var switchRotate: Switch

    private lateinit var rgGear: RadioGroup

    private var currentGear = 1 // 当前档位(默认1挡)

    private var previousGear = 1 // 上一个档位(用于判断过渡方向)

    private var isRotating = false // 是否旋转中

    private var currentRotationAngle = 0f // 当前旋转角度(衔接用)

    private var rotationAnimationSet: AnimationSet? = null // 动画集

    // 固定参数

    private val TRANSITION_DURATION = 500L // 过渡时间(500ms)

    private val ROTATE_ANGLE_TRANSITION = 60f // 过渡动画旋转角度(平缓适配)

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_rotation)

        initView()

        initListener()

    }

    private fun initView() {

        ivRotating = findViewById(R.id.iv_rotating)

        switchRotate = findViewById(R.id.switch_rotate)

        rgGear = findViewById(R.id.rg_gear)

    }

    private fun initListener() {

        // 档位切换监听(核心:记录上一档位,判断过渡方向)

        rgGear.setOnCheckedChangeListener { _, checkedId ->

            previousGear = currentGear // 先保存上一档位

            currentGear = when (checkedId) {

                R.id.rb_gear1 -> 1

                R.id.rb_gear2 -> 2

                R.id.rb_gear3 -> 3

                else -> 1

            }

            if (isRotating) {

                restartRotationWithDirection() // 按方向启动过渡动画

            }

        }

        // 启停开关监听

        switchRotate.setOnCheckedChangeListener { _, isChecked ->

            isRotating = isChecked

            if (isChecked) {

                // 首次启动:默认加速过渡(从静止到当前档位)

                startRotationWithTransition(accelerate = true)

            } else {

                stopRotation()

            }

        }

    }

    /**

    * 按档位切换方向,重启动画集

    */

    private fun restartRotationWithDirection() {

        stopRotation() // 停止旧动画,记录当前角度

        // 判断方向:当前档位 > 上一档位 = 加速;反之 = 减速

        val needAccelerate = currentGear > previousGear

        startRotationWithTransition(needAccelerate)

    }

    /**

    * 启动动画集(含方向适配的过渡动画+匀速动画)

    * @param accelerate 是否加速过渡(true=加速,false=减速)

    */

    private fun startRotationWithTransition(accelerate: Boolean) {

        // 1. 获取当前档位的匀速周期(毫秒/圈)

        val uniformDuration = (getGearCycle() * 1000).toLong()

        // 2. 计算过渡动画的绝对起止角度(避免相对角度歧义)

        val transitionStartAngle = currentRotationAngle

        val transitionEndAngle = currentRotationAngle + ROTATE_ANGLE_TRANSITION

        // 3. 创建方向适配的过渡动画

        val transitionAnim = RotateAnimation(

            transitionStartAngle, // 起始角度:当前角度

            transitionEndAngle, // 结束角度:当前角度+过渡角度

            Animation.RELATIVE_TO_SELF, 0.5f, // 旋转中心:自身中心

            Animation.RELATIVE_TO_SELF, 0.5f

        ).apply {

            duration = TRANSITION_DURATION

            // 按方向切换插值器

            interpolator = if (accelerate) {

                AccelerateDecelerateInterpolator() // 加速过渡(低档→高档)

            } else {

                DecelerateInterpolator() // 减速过渡(高档→低档)

            }

            fillAfter = true // 保持过渡后的角度

            repeatCount = 0 // 仅执行1次

        }

        // 4. 创建匀速动画(绝对角度,无缝衔接)

        val uniformAnim = RotateAnimation(

            transitionEndAngle, // 起始角度:过渡动画结束角度

            transitionEndAngle + 360f, // 结束角度:再转一圈

            Animation.RELATIVE_TO_SELF, 0.5f,

            Animation.RELATIVE_TO_SELF, 0.5f

        ).apply {

            duration = uniformDuration

            interpolator = LinearInterpolator() // 纯匀速

            fillAfter = true

            repeatCount = Animation.INFINITE // 无限循环

            repeatMode = Animation.RESTART

        }

        // 5. 动画集串联(按顺序执行)

        rotationAnimationSet = AnimationSet(true).apply {

            addAnimation(transitionAnim)

            addAnimation(uniformAnim)

            isFillAfter = true

        }

        // 启动动画集

        ivRotating.startAnimation(rotationAnimationSet)

    }

    /**

    * 停止旋转(记录当前角度,用于下次衔接)

    */

    private fun stopRotation() {

        currentRotationAngle = ivRotating.rotation % 360f // 取余360,避免角度溢出

        rotationAnimationSet?.cancel()

        ivRotating.clearAnimation()

        rotationAnimationSet = null

    }

    /**

    * 获取当前档位的旋转周期(秒/圈)

    */

    private fun getGearCycle(): Float {

        return when (currentGear) {

            1 -> 3f // 1挡:3秒/圈

            2 -> 2f // 2挡:2秒/圈

            3 -> 1f // 3挡:1秒/圈

            else -> 3f

        }

    }

    override fun onDestroy() {

        super.onDestroy()

        stopRotation()

    }

}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容