Kotlin实现RotateAnimation转盘动画点击spinBtn无响应问题求助
核心问题定位
- 控件初始化顺序错误,点击事件未成功绑定
- 随机数范围错误存在数组越界风险
- ViewModel越权处理视图层动画逻辑,不符合架构规范
修复方案
1. 修正GameFragment的视图初始化逻辑
你已经引入了ViewBinding,直接通过binding对象访问控件即可,不需要手动调用findViewById,同时调整初始化顺序,先inflate得到binding对象再配置控件逻辑:
class GameFragment : Fragment() { private lateinit var gameViewModel: GameViewModel private var _binding: GameFragmentBinding? = null // 仅在onCreateView和onDestroyView之间有效 private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { // 先 inflate 得到视图实例 _binding = GameFragmentBinding.inflate(inflater, container, false) gameViewModel = ViewModelProvider(this).get(GameViewModel::class.java) gameViewModel.getDegreesForSectors() // 直接通过binding访问控件,绑定点击事件 binding.spinBtn.setOnClickListener { if (!gameViewModel.isSpinning) { spinWheel() } } return binding.root } // 动画属于视图层逻辑,放在Fragment中实现 private fun spinWheel() { gameViewModel.isSpinning = true val targetDegree = gameViewModel.getRandomTargetDegree() val rotateAnimation = RotateAnimation( 0f, (360 * gameViewModel.fieldCount + targetDegree).toFloat(), RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f ).apply { duration = 3600 fillAfter = true interpolator = DecelerateInterpolator() setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) {} override fun onAnimationEnd(animation: Animation) { gameViewModel.isSpinning = false // 此处可添加旋转结束后的业务逻辑,比如读取中奖结果 } override fun onAnimationRepeat(animation: Animation) {} }) } // 注意和你的布局id对应,ViewBinding会自动把下划线转为驼峰命名 binding.spinningWheel.startAnimation(rotateAnimation) } override fun onDestroyView() { super.onDestroyView() _binding = null } }
2. 修正GameViewModel的逻辑,仅保留业务数据计算
class GameViewModel : ViewModel() { private val fields = arrayOf("1","2","3","4","5","6","7") private val fieldDegrees = IntArray(fields.size) var isSpinning = false // 对外暴露扇区数量供动画计算使用 val fieldCount get() = fields.size fun getDegreesForSectors(){ val oneFieldDegree = 360 / fields.size for (i in fields.indices){ fieldDegrees[i] = (i+1) * oneFieldDegree } } // 修正随机数范围为0至fields.size-1,避免数组越界 fun getRandomTargetDegree(): Int { val randomIndex = (0 until fields.size).random() return fieldDegrees[randomIndex] } }
可选优化提示
如果后续需要支持不等分扇区,仅需修改getDegreesForSectors中的角度分配逻辑即可,无需改动视图层的动画代码。
内容的提问来源于stack exchange,提问作者Daniel Diamant
相关产品推荐
相关产品推荐

