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

基于Android Java实现Apple Music风格动态流体模糊背景

复刻Apple Music动态流体模糊背景效果

我一直在研究如何复刻Apple Music的背景效果——提取专辑封面颜色,制作带有提取色彩的动态缓慢流动模糊背景。目前已编写了提取颜色的ColorExtractor类,但不清楚如何实现该流体模糊动画效果。

已完成的颜色提取代码

public class ColorExtractor {

    private int previousColor; // Initial fallback color (black)
    private long animationDuration; // Duration in milliseconds
    private Interpolator interpolator; // Interpolator for animation

    public ColorExtractor(Context context) {
        this.animationDuration = 300; // Default duration
        this.interpolator = new DecelerateInterpolator(); // Default interpolator
    }

    public interface ColorCallback {
        void onColorExtracted(int animatedColor);
    }

    /**
     * Set the animation duration for the color transition.
     * @param duration Animation duration in milliseconds.
     */
    public void setAnimationDuration(long duration) {
        this.animationDuration = duration;
    }

    /**
     * Set a custom interpolator for the color transition.
     * @param interpolator Custom interpolator for the animation.
     */
    public void setInterpolator(Interpolator interpolator) {
        this.interpolator = interpolator;
    }

    public void extractDominantColor(byte[] imageData, ColorCallback callback) {
        Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

        if (bitmap != null) {
            Palette.from(bitmap).generate(palette -> {
                if (palette != null) {
                    int newColor = getColorFromPalette(palette);
                    if (newColor != previousColor) { // Only animate if the color changes
                        animateColorChange(previousColor, newColor, callback);
                        previousColor = newColor; // Update previous color to the new one
                    } else {
                        callback.onColorExtracted(previousColor); // No animation if colors are the same
                    }
                    bitmap.recycle(); // Clean up bitmap to free memory
                } else {
                    callback.onColorExtracted(previousColor); // Fallback to previous color
                }
            });
        } else {
            callback.onColorExtracted(previousColor); // Fallback to previous color
        }
    }

    private int getColorFromPalette(Palette palette) {
        // Create a list of swatch providers
        List<Palette.Swatch> swatches = new ArrayList<>();
        swatches.add(palette.getLightMutedSwatch());
        swatches.add(palette.getMutedSwatch());
        swatches.add(palette.getLightVibrantSwatch());
        swatches.add(palette.getVibrantSwatch());

        // Shuffle the list for random selection order
        Collections.shuffle(swatches);

        // Iterate over shuffled swatches and return the first available color
        for (Palette.Swatch swatch : swatches) {
            if (swatch != null) {
                return swatch.getRgb();
            }
        }

        // If no suitable swatch is found, use the last known color instead
        return previousColor;
    }

    private void animateColorChange(int startColor, int endColor, ColorCallback callback) {
        ValueAnimator colorAnimator = ValueAnimator.ofArgb(startColor, endColor);
        colorAnimator.setDuration(animationDuration); // Use the dynamic duration
        colorAnimator.setInterpolator(interpolator); // Use the dynamic interpolator

        colorAnimator.addUpdateListener(animation -> {
            int animatedColor = (int) animation.getAnimatedValue();
            callback.onColorExtracted(animatedColor); // Provide the smooth interpolated color
        });

        colorAnimator.start();
    }
}

流体模糊动画实现方案

Apple Music的背景效果核心是多层叠加+色彩融合+缓慢位移动画,以下是具体实现步骤:

1. 布局层叠结构

需要四层布局叠加,保证前景内容清晰:

  • 底层:动态纯色背景(接收ColorExtractor的颜色值)
  • 中层:专辑封面的模糊镜像,承载流动动画
  • 遮罩层:半透明深色遮罩,弱化模糊层,突出前景
  • 前景层:播放控件、专辑信息等核心UI
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 动态纯色背景 -->
    <View
        android:id="@+id/color_bg_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <!-- 模糊封面层 -->
    <ImageView
        android:id="@+id/blur_cover_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <!-- 半透明遮罩 -->
    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#50000000"/>

    <!-- 前景内容区 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="24dp"
        android:gravity="bottom">
        <!-- 这里放置播放控件、专辑名称等UI -->
    </LinearLayout>
</FrameLayout>

2. 生成模糊封面图

使用Android系统的RenderScript实现高效模糊,模糊半径建议设为15-25,平衡效果与性能:

private Bitmap getBlurredBitmap(Bitmap original) {
    if (original == null) return null;

    RenderScript rs = RenderScript.create(this);
    Allocation input = Allocation.createFromBitmap(rs, original);
    Allocation output = Allocation.createTyped(rs, input.getType());

    ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    blurScript.setInput(input);
    blurScript.setRadius(20f); // 模糊半径,可按需调整
    blurScript.forEach(output);

    Bitmap blurredBitmap = Bitmap.createBitmap(original.getWidth(), original.getHeight(), original.getConfig());
    output.copyTo(blurredBitmap);

    // 释放资源
    input.destroy();
    output.destroy();
    blurScript.destroy();
    rs.destroy();

    return blurredBitmap;
}

3. 实现缓慢流动动画

给模糊层添加低幅度、长周期的平移+缩放动画,模拟自然流动感:

private void startFluidAnimation(ImageView blurView) {
    // 水平平移动画:左右小幅度循环移动
    ObjectAnimator translateX = ObjectAnimator.ofFloat(blurView, "translationX", 0f, 40f, 0f, -40f, 0f);
    translateX.setDuration(22000); // 22秒一个周期,节奏平缓
    translateX.setRepeatCount(ValueAnimator.INFINITE);
    translateX.setInterpolator(new LinearInterpolator());

    // 垂直平移动画:上下小幅度循环移动,与水平周期错开
    ObjectAnimator translateY = ObjectAnimator.ofFloat(blurView, "translationY", 0f, 30f, 0f, -30f, 0f);
    translateY.setDuration(18000);
    translateY.setRepeatCount(ValueAnimator.INFINITE);
    translateY.setInterpolator(new LinearInterpolator());

    // 轻微缩放动画:增强空间流动感
    ObjectAnimator scaleX = ObjectAnimator.ofFloat(blurView, "scaleX", 1f, 1.06f, 1f);
    scaleX.setDuration(20000);
    scaleX.setRepeatCount(ValueAnimator.INFINITE);
    scaleX.setInterpolator(new DecelerateInterpolator());

    ObjectAnimator scaleY = ObjectAnimator.ofFloat(blurView, "scaleY", 1f, 1.06f, 1f);
    scaleY.setDuration(24000);
    scaleY.setRepeatCount(ValueAnimator.INFINITE);
    scaleY.setInterpolator(new AccelerateInterpolator());

    // 组合动画,同步播放
    AnimatorSet animSet = new AnimatorSet();
    animSet.playTogether(translateX, translateY, scaleX, scaleY);
    animSet.start();
}

4. 结合ColorExtractor实现色彩融合

在ColorCallback中同步更新背景色和模糊层的颜色滤镜,让模糊图与提取色自然融合:

// 初始化ColorExtractor,延长过渡时间更贴合Apple Music风格
ColorExtractor extractor = new ColorExtractor(this);
extractor.setAnimationDuration(1200);

extractor.extractDominantColor(imageData, animatedColor -> {
    // 更新纯色背景
    findViewById(R.id.color_bg_view).setBackgroundColor(animatedColor);
    
    // 给模糊层添加颜色滤镜,融合提取的主色调
    ImageView blurCover = findViewById(R.id.blur_cover_view);
    blurCover.setColorFilter(animatedColor, PorterDuff.Mode.SCREEN);
});

// 生成模糊封面并启动动画
Bitmap originalCover = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
Bitmap blurredCover = getBlurredBitmap(originalCover);
ImageView blurCoverView = findViewById(R.id.blur_cover_view);
blurCoverView.setImageBitmap(blurredCover);
startFluidAnimation(blurCoverView);

性能优化建议

  • 模糊半径不要超过25,避免过度消耗GPU资源;可根据设备性能动态调整
  • 动画周期设置为15-30秒,保证流动效果平缓不突兀
  • 及时回收Bitmap资源:模糊完成后回收原始封面图,避免内存泄漏
  • 低性能设备可关闭缩放动画,只保留平移效果

内容的提问来源于stack exchange,提问作者wayne chirwa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:15:01