Android中如何将视图置于另一视图位置并实现缩放动画?
解决2048游戏缩放动画视图定位问题
核心问题分析
你把动画视图直接加到了game_grid_layout(垂直LinearLayout)中,LinearLayout会按布局方向将新视图排列在底部,而非悬浮覆盖原视图;同时你使用translationX/Y的方式错误,没有基于父容器的正确坐标计算偏移。
解决方案步骤
1. 调整布局结构
将game_grid_layout包裹在一个全屏FrameLayout中,这样动画视图可以和游戏网格同级,实现悬浮覆盖:
<FrameLayout android:id="@+id/animation_container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <LinearLayout android:id="@+id/game_grid_layout" android:layout_width="280dp" android:layout_height="280dp" android:layout_marginTop="16dp" android:background="@color/game_container" android:orientation="vertical" android:layout_gravity="center"> <!-- 原网格内容保持不变 --> </LinearLayout> </FrameLayout>
2. 正确计算动画视图的位置
获取原视图相对于外层FrameLayout的坐标,设置动画视图的布局参数和位置:
// 外层FrameLayout val animationContainer = findViewById<FrameLayout>(R.id.animation_container) // 原视图(示例为第一个单元格,替换为你需要动画的视图) val originalView = findViewById<FrameLayout>(R.id.grid_container_0_0) // 创建动画视图(和原视图内容一致,替换为你的单元格布局) val viewToAnimate = LayoutInflater.from(this).inflate(R.layout.cell_item, animationContainer, false) // 复制原视图的宽高 val width = originalView.width val height = originalView.height // 计算原视图相对于animationContainer的坐标 val originalLoc = IntArray(2) originalView.getLocationInWindow(originalLoc) val containerLoc = IntArray(2) animationContainer.getLocationInWindow(containerLoc) val offsetX = originalLoc[0] - containerLoc[0] val offsetY = originalLoc[1] - containerLoc[1] // 设置动画视图的布局参数 val params = FrameLayout.LayoutParams(width, height) params.leftMargin = offsetX params.topMargin = offsetY animationContainer.addView(viewToAnimate, params) // 设置层级,确保在网格上方 ViewCompat.setElevation(viewToAnimate, 2f)
3. 修复缩放动画逻辑
确保缩放以视图中心为基准,并在动画结束后移除视图:
val mergeAnim = ValueAnimator.ofFloat(1f, 2f) mergeAnim.addUpdateListener { animation -> viewToAnimate.scaleX = animation.animatedValue as Float viewToAnimate.scaleY = animation.animatedValue as Float } mergeAnim.repeatCount = 1 mergeAnim.repeatMode = ValueAnimator.REVERSE mergeAnim.addListener(object : Animator.AnimatorListener { override fun onAnimationEnd(animation: Animator?) { // 动画结束后移除视图,避免内存泄漏 animationContainer.removeView(viewToAnimate) } override fun onAnimationStart(animation: Animator?) {} override fun onAnimationCancel(animation: Animator?) {} override fun onAnimationRepeat(animation: Animator?) {} }) val animatorSet = AnimatorSet() animatorSet.interpolator = DecelerateInterpolator(1f) animatorSet.duration = 100 animatorSet.play(mergeAnim) animatorSet.start()
关键注意点
- 必须将动画视图添加到FrameLayout容器中,而非原LinearLayout网格,否则会被线性布局排列,无法悬浮。
- 坐标计算要基于动画容器的位置,避免因状态栏、导航栏导致的偏移错误。
- 动画结束后记得移除视图,避免内存泄漏。
内容的提问来源于stack exchange,提问作者יששכר בן דוד
相关产品推荐
相关产品推荐

