最近项目里有个功能点,需要使用定制seekbar调节媒体音量,不能使用【按物理音量上下键】弹出的系统dialog做音量调节。
有位同学也做过类似的demo,https://blog.csdn.net/a1533588867/article/details/53738027 ,这个demo虽然可以很好地做到拖动定制的seekbar或者按物理音量上下键调节媒体音量,但是我觉得这个demo实用性不太够:这个demo是在一个activity显示seekbar,但是实际开发中,我们都是在activity上弹一个dialog显示seekbar的,因为activity的内容还得驻留,比如观看视频,在玩游戏等。所以在这个demo基础上进行改进。
因此我需要继承AlertDialog,设置自己的内容view,重写onKeyDown方法,设置dialog的位置等...... 然而在过程中遇到了不少坑,记录下。
坑1:设置Dialog 位置,横坐标位置设置无效。(AdjustVolumeDialog.java)
// 设置dialog中view 的位置
Window window = getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
/**
* 无论x设置100,200,300,400...... 效果还是一样,需要给dialog设置style theme!!
*/
// lp.gravity = Gravity.TOP | Gravity.LEFT;
// lp.x = 200;
// lp.y = 100;
window.setAttributes(lp);
原因:没有为Dialog设置style theme
自定义Dialog在构造时需要设置style theme : (MainActivity.java)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 需要为dialog设置一个style
adjustVolumeDialog = new AdjustVolumeDialog(this, R.style.MyDialogStyle);
// 启动一个service 播放媒体音乐
startService(new Intent(this, VolumeTestService.class));
}
<style name="MyDialogStyle">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
坑2:setContentView的时机在Dialog的构造方法时,内容view不可见。
解决:setContentView的时机需要放到Dialog的onCreate() (AdjustVolumeDialog.java)
/**
* 在onCreate方法里面 setContentView() 否则dialog的自定义view 显示不出来
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initParams();
initView();
}
坑3: 广播的注册和销毁时机 不对导致泄漏。(AdjustVolumeDialog.java)
/**
* dialog显示时回调
* 广播注册
*/
@Override
public void show() {
super.show();
IntentFilter filter = new IntentFilter() ;
filter.addAction("android.media.VOLUME_CHANGED_ACTION") ;
getContext().registerReceiver(volumeReceiver, filter) ;
}
/**
* dialog消失时回调
* 广播反注册
*/
@Override
public void dismiss() {
getContext().unregisterReceiver(volumeReceiver);
super.dismiss();
}
坑4:在Activity 实现onKeyDown 方法:按物理音量设置音量;Dialog中的BroadcastReceiver.onReceive()没有调用。
原因:弹出dialog后,按物理音量键的事件被dialog先消费了(并且没有重写dialog的onKeyDown),没有到activity。因此应该重写dialog的onKeyDown 设置媒体音量值。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN) {
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0);
}else if (event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
}else if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
dismiss();
}
return true;
}
我的demo:
1)在MainActivity打开的时候 启动一个service播放本地音乐。
2)按物理音量上下键弹出 自定义的Dialog,拖动Dialog上的seekbar或者按物理上下键可以调节媒体音量,从而控制播放的本地音乐声音。
效果图