双RecyclerView布局中,实现上方RecyclerView高度动画切换至MATCH_PARENT
实现RecyclerView高度平滑过渡到MATCH_PARENT的动画方案
嘿,我懂你想要的效果——点击「更多」按钮让上方RecyclerView平滑展开占满父容器对吧?你的ValueAnimator思路完全正确,我来帮你把代码补全,还会加上一些实用的细节处理:
核心思路
要实现这个动画,得先拿到两个关键高度值:
- 上方RecyclerView的当前实际高度
- 父容器的可用高度(也就是MATCH_PARENT对应的真实像素值)
然后用ValueAnimator在这两个值之间做平滑过渡,实时更新RecyclerView的布局高度即可。
完整代码实现
// 定义变量记录当前状态:false=收起状态,true=已展开 private boolean isTopRvExpanded = false; // 「更多」按钮的点击事件逻辑 binding.moreLl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 获取上方RecyclerView的父容器(根据你的实际布局调整类型,比如LinearLayout/ConstraintLayout) ViewGroup parentLayout = (ViewGroup) binding.topRecyclerView.getParent(); // 计算父容器的可用高度:父容器总高度 - 下方RecyclerView高度 - 「更多」按钮高度 int parentTotalHeight = parentLayout.getHeight(); int bottomRvHeight = binding.bottomRecyclerView.getHeight(); int moreBtnHeight = binding.moreLl.getHeight(); int targetExpandHeight = parentTotalHeight - bottomRvHeight - moreBtnHeight; // 获取上方RecyclerView当前的高度 int currentHeight = binding.topRecyclerView.getHeight(); // 根据当前状态确定动画的起始和结束值 int startHeight = isTopRvExpanded ? targetExpandHeight : currentHeight; int endHeight = isTopRvExpanded ? currentHeight : targetExpandHeight; // 创建高度过渡动画 ValueAnimator heightAnim = ValueAnimator.ofInt(startHeight, endHeight); heightAnim.setDuration(350); // 设置动画时长,单位毫秒 heightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animator) { int animatedHeight = (int) animator.getAnimatedValue(); // 更新RecyclerView的布局高度 ViewGroup.LayoutParams layoutParams = binding.topRecyclerView.getLayoutParams(); layoutParams.height = animatedHeight; binding.topRecyclerView.setLayoutParams(layoutParams); } }); // 动画结束后的收尾处理 heightAnim.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) {} @Override public void onAnimationEnd(Animator animator) { if (!isTopRvExpanded) { // 展开状态下,把高度设为MATCH_PARENT,避免后续布局变化时高度异常 ViewGroup.LayoutParams layoutParams = binding.topRecyclerView.getLayoutParams(); layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; binding.topRecyclerView.setLayoutParams(layoutParams); } // 切换状态标记 isTopRvExpanded = !isTopRvExpanded; } @Override public void onAnimationCancel(Animator animator) {} @Override public void onAnimationRepeat(Animator animator) {} }); // 启动动画 heightAnim.start(); } });
关键细节说明
- 父容器高度计算:我这里默认父容器是LinearLayout,如果你用的是ConstraintLayout,建议通过
ViewTreeObserver确保视图测量完成后再获取高度,避免拿到0值:binding.topRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { binding.topRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // 在这里计算父容器高度和执行动画逻辑 } }); - 状态切换:加入
isTopRvExpanded变量,实现点击「更多」按钮在展开/收起之间切换的交互,更符合用户预期。 - 动画收尾:动画结束后把展开状态的RecyclerView高度设为
MATCH_PARENT,这样后续父容器尺寸变化(比如屏幕旋转)时,RecyclerView能自动适应,不会停留在固定像素高度。 - 布局参数类型:确保
ViewGroup.LayoutParams和父容器类型匹配,比如父容器是LinearLayout就用LinearLayout.LayoutParams,避免出现类型转换异常。
这样就能实现流畅的高度过渡动画啦!
内容的提问来源于stack exchange,提问作者Mustafa Lokhandwala
相关产品推荐
相关产品推荐

