Android音乐播放声音淡入淡出的实现
2018年12月27日


思路: 调用如下API接口

MediaPlayer.setVolume(left, right);// 左右声道,值为0~1

比如,让音量从 0 增加到100%,分为10次增加,则可以调10次上面的接口(每次间隔0.2秒,一共2秒内音量增加到100%),如下所示:

MediaPlayer.setVolume(0.1, 0.1);
MediaPlayer.setVolume(0.2, 0.2);
MediaPlayer.setVolume(0.3, 0.3);
...
MediaPlayer.setVolume(1.0, 1.0); // 音量100%

实现方式一,通过 android.os.Handler 发送 android.os.Message 消息,代码如下:

import android.os.Handler;
import android.os.Message;

public class MuteVolumeManager {
    // action
    private static final int ACTION_RESTORE_VALUE = 1000;
    private static final int ACTION_STOP_VALUE = 1001;
    // 淡出与淡出时间
    private int restoreTime = 5000; // 恢复 淡入时间为5秒
    private int stopTime = 1000; // 静音 淡出时间为1秒
    private float muteCurVolume = 0f;
    private float muteTargetVolume = 0f;
    private float unMuteCurVolume = 0f;
    private float unMuteTargetVolume = 0f;
    private boolean isMuteing = false;
    private boolean isUnMuteing = false;
    // listenter
    private VolumeListenter volumeListenter;
    // handler control
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == ACTION_RESTORE_VALUE) {
                if (muteCurVolume < muteTargetVolume) {
                    muteCurVolume += 0.1f;
                    if (muteCurVolume > 1) {
                        muteCurVolume = 1;
                    }
                    // Logger.d("siven","实时恢复音量 " + muteCurVolume);
                    if (muteCurVolume < muteTargetVolume) {
                        notifyVolumeChange(muteCurVolume);// 最大1.0,是个百分比
                        handler.sendEmptyMessageDelayed(ACTION_RESTORE_VALUE, restoreTime / 10);
                    } else {
                        muteCurVolume = muteTargetVolume;
                        notifyVolumeChange(muteCurVolume);// 最大1.0,是个百分比
                        if (volumeListenter != null &&
                                isUnMuteing) volumeListenter.onCompleteUnMute(muteCurVolume);
                        isUnMuteing = false;
                    }
                } else if (muteCurVolume >= muteTargetVolume) {
                    notifyVolumeChange(muteTargetVolume); //最大1.0,是个百分比
                    // Logger.d("siven","实时恢复音量 " + muteTargetVolume);
                    if (volumeListenter != null &&
                            isUnMuteing) volumeListenter.onCompleteUnMute(muteCurVolume);
                    isUnMuteing = false;
                }
            } else if (msg.what == ACTION_STOP_VALUE) {
                if (unMuteCurVolume > unMuteTargetVolume) {
                    unMuteCurVolume -= 0.1;
                    if (unMuteCurVolume < 0) {
                        unMuteCurVolume = 0;
                    }
                    notifyVolumeChange(unMuteCurVolume);
                    // Logger.d("siven","实时静音音量 " + unMuteCurVolume);
                    if (unMuteCurVolume > unMuteTargetVolume) {
                        handler.sendEmptyMessageDelayed(ACTION_STOP_VALUE, stopTime / 10);//0.5秒恢复音量100%音量
                    } else {
                        if (volumeListenter != null &&
                                isMuteing) volumeListenter.onCompleteMute(unMuteCurVolume);
                        isMuteing = false;
                    }
                } else {
                    notifyVolumeChange(0f);//静音
                    if (volumeListenter != null &&
                            isMuteing) volumeListenter.onCompleteMute(unMuteCurVolume);
                    isMuteing = false;
                }

            }
        }
    };

    public void setVolumeListenter(VolumeListenter volumeListenter) {
        this.volumeListenter = volumeListenter;
    }

    /**
     * 恢复音量,淡入效果
     */
    public void unMute(float curVolume, float tagetVolume) {
        if (isUnMuteing) return;
        isUnMuteing = true;
        this.muteTargetVolume = tagetVolume;
        this.muteCurVolume = curVolume;
        handler.sendEmptyMessage(ACTION_RESTORE_VALUE);
    }

    /**
     * 静音,淡出效果
     */
    public void mute(float curVolume) {
        if (isMuteing) return;
        isMuteing = true;
        this.unMuteCurVolume = curVolume;
        this.unMuteTargetVolume = 0f;
        handler.sendEmptyMessage(ACTION_STOP_VALUE);
    }

    private void notifyVolumeChange(float volume) {
        if (volumeListenter != null) {
            volumeListenter.onVolumeChange(volume);
        }
    }

    public interface VolumeListenter {
        void onCompleteMute(float curVolume);
        void onCompleteUnMute(float curVolume);
        void onVolumeChange(float volume);
    }
}

调用方法示例如下:

mMediaPlayer.start();
setVolumeFade(mMediaPlayer);
mMediaPlayer.setVolume(0f, 0f);
volumeManager.unMute(0f, 1f);

private void setVolumeFade(final IjkMediaPlayer mediaPlayer) {
    volumeManager.setVolumeListenter(new MuteVolumeManager.VolumeListenter() {
        public void onCompleteMute(float curVolume) {
            Log.i("siven", "静音完成,当前音量为: " + curVolume);
        }
        public void onCompleteUnMute(float curVolume) {
            Log.i("siven", "恢复音量完成,当前音量为: " + curVolume);
        }
        public void onVolumeChange(float volume) {
            if (mediaPlayer != null) {
                // 动态设置音量
                mediaPlayer.setVolume(volume, volume);
            }
        }
    });
}


实现方式二,使用 android.animation.ValueAnimator 淡入淡出工具类,如下:

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.media.MediaPlayer;
import android.support.annotation.Nullable;
import android.view.animation.LinearInterpolator;

/**
 * 音量淡入
 */
public class FadeIn {

    public static void volumeGradient(final MediaPlayer mediaPlayer,
                                      final float from, final float to) {
        ValueAnimator animator = ValueAnimator.ofFloat(from, to);
        animator.setDuration(6000); // 淡入时间
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator it) {
                float volume = (float) it.getAnimatedValue();
                try {
                    // 此时可能 mediaPlayer 状态发生了改变
                    //,所以用try catch包裹,一旦发生错误,立马取消
                    mediaPlayer.setVolume(volume, volume);
                } catch (Exception e) {
                    it.cancel();
                }
            }

        });

        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }
            @Override
            public void onAnimationEnd(Animator animation) {
//                mediaPlayer.setVolume(from, from);
//                if (doneCallBack != null) {
//                    doneCallBack.onComplete();
//                }
            }
            @Override
            public void onAnimationCancel(Animator animation) {
//                try {
//                    mediaPlayer.setVolume(from, from);
//                } catch (Exception e) {
//                    //忽略
//                }
            }
            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
        animator.start();
    }
}

调用方法如下:

FadeIn.volumeGradient(mMediaPlayer, 0f, 1f);

推荐使用第二种方式。