You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:16:58