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

如何实现类似WhatsApp的展开式Collapsing Toolbar图片模糊效果?

实现WhatsApp风格的Collapsing Toolbar标题遮罩效果

我懂你这种困扰!浅色背景图上的白色标题确实完全看不清,给整张图加tint又毁了原图的质感,WhatsApp那种只在标题区域做模糊/渐变遮罩的思路确实聪明多了。下面给你两种实用的实现方式,按需选择:

方法一:添加渐变遮罩层(简单易实现)

这种方式用渐变层覆盖在图片底部的标题区域,既不影响图片整体观感,又能让白色标题清晰显示,是最省心的方案:

  1. 修改你的CollapsingToolbarLayout布局,在加载图片的ImageView上方添加一个遮罩View,放在底部对应标题的高度位置:
<com.google.android.material.appbar.CollapsingToolbarLayout
    android:id="@+id/collapsing_toolbar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:contentScrim="@color/colorPrimary"
    app:layout_scrollFlags="scroll|exitUntilCollapsed"
    app:title="你的标题">

    <!-- Picasso加载的图片 -->
    <ImageView
        android:id="@+id/toolbar_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <!-- 渐变遮罩层 -->
    <View
        android:layout_width="match_parent"
        android:layout_height="120dp" <!-- 对应标题区域的高度,可按需调整 -->
        android:layout_gravity="bottom"
        android:background="@drawable/gradient_mask"/>

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:layout_collapseMode="pin"/>

</com.google.android.material.appbar.CollapsingToolbarLayout>
  1. 在res/drawable下创建gradient_mask.xml文件,定义从透明到半透明黑色的垂直渐变:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="@android:color/transparent"
        android:endColor="#80000000" <!-- 半透明黑色,透明度可调整 -->
        android:angle="90"/>
</shape>

方法二:实现模糊背景层(贴近WhatsApp原生效果)

如果想要完全复刻WhatsApp的模糊效果,可以对图片的底部标题区域进行模糊处理,步骤如下:

  1. 首先在项目的build.gradle(Module级别)中添加RenderScript依赖,用于模糊处理:
implementation "androidx.renderscript:renderscript:16.0.1"
  1. 修改布局,把遮罩View换成ImageView,用来显示模糊后的图片区域:
<ImageView
    android:id="@+id/mask_view"
    android:layout_width="match_parent"
    android:layout_height="120dp"
    android:layout_gravity="bottom"
    android:scaleType="centerCrop"/>
  1. 在代码中监听Picasso的图片加载完成事件,裁剪图片底部区域并做模糊处理:
ImageView toolbarImage = findViewById(R.id.toolbar_image);
ImageView maskView = findViewById(R.id.mask_view);

Picasso.get()
    .load("你的网络图片URL")
    .into(toolbarImage, new Callback() {
        @Override
        public void onSuccess() {
            // 获取加载完成的图片Bitmap
            Bitmap originalBitmap = ((BitmapDrawable) toolbarImage.getDrawable()).getBitmap();
            // 计算标题区域的高度(这里用120dp转成像素)
            int titleHeight = (int) getResources().getDimension(R.dimen.title_height);
            // 裁剪图片底部的标题区域
            Bitmap croppedBitmap = Bitmap.createBitmap(
                originalBitmap,
                0,
                originalBitmap.getHeight() - titleHeight,
                originalBitmap.getWidth(),
                titleHeight
            );
            // 对裁剪后的区域进行模糊处理
            Bitmap blurredBitmap = blurBitmap(croppedBitmap, YourActivity.this);
            // 设置到遮罩ImageView上
            maskView.setImageBitmap(blurredBitmap);
        }

        @Override
        public void onError(Exception e) {
            // 处理图片加载失败的情况
        }
    });
  1. 添加模糊处理的工具方法:
private Bitmap blurBitmap(Bitmap bitmap, Context context) {
    RenderScript rs = RenderScript.create(context);
    // 创建和原图尺寸一致的空白Bitmap用于存储模糊结果
    Bitmap blurredBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

    Allocation input = Allocation.createFromBitmap(rs, bitmap);
    Allocation output = Allocation.createFromBitmap(rs, blurredBitmap);

    // 初始化模糊脚本
    ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    blurScript.setInput(input);
    blurScript.setRadius(25f); // 模糊程度,数值越大越模糊,建议15-30之间
    blurScript.forEach(output);

    // 将模糊结果复制到目标Bitmap
    output.copyTo(blurredBitmap);
    rs.destroy();
    return blurredBitmap;
}

额外优化:根据折叠状态动态调整遮罩

可以监听AppBar的折叠状态,在Toolbar折叠时隐藏遮罩(此时标题在contentScrim上,不需要遮罩),展开时显示:

AppBarLayout appBarLayout = findViewById(R.id.app_bar);
appBarLayout.addOnOffsetChangedListener((appBar, verticalOffset) -> {
    // 计算折叠百分比
    float collapsePercentage = (float) Math.abs(verticalOffset) / appBar.getTotalScrollRange();
    // 折叠时降低遮罩透明度,展开时恢复
    maskView.setAlpha(1 - collapsePercentage);
});

内容的提问来源于stack exchange,提问作者Kiran Suvarna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:03:31