简单实现音量对话框小尝试

简单实现音量对话框小尝试

需求分析

工作需要实现一个在播放音乐时,音量键按下后弹出程序自己的音量控制界面,由于对android还不太熟悉,就当写个小Demo练练手吧。

根据要求的话,需要实现如下功能点的要求

1、 拦截系统音量键

2、 用SeekBar简单实现音量控制界面(采用对话框的形式来实现)

3、 点击对话框外内容,对话框自动消失

4、 对话框内一定时间内无事件(3s),对话框自动消失

下面分步来实现这个小Demo程序。

拦截系统音量键

本来想在View中拦截音量键的,但是不知道为什么在ViewonKeyDown事件拦截不到,后来查了下网上的说法,如果需要让一个View响应按键事件,必须按键的时候焦点位于这个View上面,我尝试了下,假设这个View类实例为test,则可以通过下列方式设置焦点

//test.setFocusable(true);

test.setFocusableInTouchMode(true);

test.requestFocus();

网上也有人说通过SetFocusable设置的就可以了,但是我试了下不行,必须得用setFocusableInTouchMode然后调用requestFocus,我在测试时放在OnCreate方法中调用,也有人说放在OnCreate中有时候也不行,因为此时View还没有被显示出来。后来问了下同事,说是这种在View中拦截OnKeyDown的方式是并不推荐的方法,有违面向对象的原则,OnKeyDown这种事件本身就应该交由Activity等类来拦截,然后需要处理的操作,就通过给View类配备setget方法的形式来设置,想想也是很有道理的。

系统音量键的拦截网上代码很多,在这里也不多说,直接上代码吧,其中的VolumeSetDialog就是自己的音量控制对话框类。

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {

VolumeSetDialog vDlg = new VolumeSetDialog(this);

vDlg.show();

return true;

} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {

VolumeSetDialog vDlg = new VolumeSetDialog(this);

vDlg.show();

return true;

} else {

return super.onKeyDown(keyCode, event);

}

}

这里真没有什么补充的,因为我的对话框弹出时,跟系统的音量控制对话框是互斥的,所以onKeyDown返回为true,否则还是会显示出系统音量对话框出来哦。

音量控制对话

系统提供的SeekBar是横向的,我本来以为可以通过类似android:orientation="vertical"的修改参数方法让其实现竖直方向,结果不行,貌似需要用自定义的seekBar,想着能力有限,就给几个链接吧,以后有需要再去看

android 竖直seekbar的案例,需要重载类

http://www.eoeandroid.com/thread-93431-1-1.html

http://blog.csdn.net/riyuegonghe/article/details/9298567

http://www.mokasocial.com/2011/02/create-a-custom-styled-ui-slider-seekbar-in-android/

我就使用默认的最简单的拖动方法产生了一个布局名为volume_dialog.xml,具体的内容如下

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/volume_layout"

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

 

    <SeekBar

        android:id="@+id/volume_seekBar"

        android:layout_width="200dp"

        android:layout_height="30dp"

        android:layout_centerInParent="true" />

</RelativeLayout>

注:上面的代码中

然后构建一个新的派生自AlertDialog的VolumeSetDialog类。在该类中,重载AlertDialogonCreate函数,具体代码如下:

@Override

protected void onCreate(Bundle savedInstanceState) {

// TODO Auto-generated method stub

super.onCreate(savedInstanceState);

LayoutInflater inflater = LayoutInflater.from(getContext());

View mRootView = getLayoutInflater().inflate(R.layout.dj_volume_dialog, null);

setContentView(mRootView);

// LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,

// LayoutParams.MATCH_PARENT);

// addContentView(mRootView, params);

mVolumeSeekBar = (SeekBar) mRootView.findViewById(R.id.volume_seekBar);

mVolumeSeekBar.setOnSeekBarChangeListener(this);

//mVolumeSeekBar.setOnClickListener(this);

//mRootView.findViewById(R.id.volume_layout).setOnClickListener(this);

 

mAudioManager = (AudioManager) this.getContext().getSystemService(Context.AUDIO_SERVICE);

mMaxMusicVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);

mCurMusicVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

mVolumeSeekBar.setMax(mMaxMusicVolume);

mVolumeSeekBar.setProgress(mCurMusicVolume);

setCancelable(true);

setCanceledOnTouchOutside(true);

}

上述代码加红色字体是我这个初学者一开始犯错误的地方。刚开始没有调用addContentView和setContentView,发现调用dlg.show的时候,界面变灰了,但是始终没有出现SeekBar,后来问了同事才知道,需要吧inflaterView加载到对话框中才能显示出来。

后面两块红色字体其实属于第三项功能了。

在对话框外点击,对话框消失

刚开始考虑问题时,想到的是在SeekBar和整个根视图上添加OnClickListener,然后重载onClick(View v)方法,判断当前点击的是否为SeekBar,假如不是SeekBar就调用dismiss函数让整个对话框消失。

后来发现,其实onClick事件压根就没有被调到,后来给布局加上了一个button,结果点击的时候onClick事件才能响应,以为要设置SeekBarclickable属性,结果设置了也是没有用。决定放弃,硬着头皮又去问同事,才知道对话框提供了setCanceledOnTouchOutside和setCancelable方法,前者设为true时,就能实现对话框外点击,对话框消失,设为false时,点击无响应;而后者则是对系统back键的响应与否,true则点击back键对话框消失。

在这里需要补充的时,原本以为布局文件要进行更改,不能使用match_parent,以为match_parent就覆盖了整个Windows,结果并非如我想的那样,应该是对话框属性默认就是将控件居中显示的,所以布局文件中就算将android:layout_centerInParent="true"属性去除,在弹出对话框显示时还是会居中显示SeekBar的。

至于具体的对话框样式,这里就不展开追究了。

对话框内一定时间内无事件(3s),对话框自动消失

这个功能的实现,可以使用TimerTimerTask来实现,不过起初想的稍微有点复杂,把TimerTask也实例化一个对象来使用以便管理取消的任务,谁知道TimerTask实例在Timer取消的时候,压根也被释放掉了,不能重用,Timer实例对象一旦cancel也是不能被再次schedule了,否则会报错,具体可以参见如下两个链接的说明

http://blog.csdn.net/snowdream86/article/details/7072530

http://www.eoeandroid.com/thread-68735-1-1.html

废话不多说,感觉android真的不用你像C++一样需要考虑得太多,他很多都已经给你弄好了,上传一个简单的控制代码吧,呵呵。

private void startTimer() {

if (mTimer != null) {

mTimer.cancel();

mTimer = null;

}

mTimer = new Timer();

 

mTimer.schedule(new TimerTask() {

@Override

public void run() {

VolumeSetDialog.this.dismiss();

mTimer.cancel();

mTimer = null;

}

}, 3000);

 

}

 

private void stopTimer() {

if (mTimer != null) {

mTimer.cancel();

mTimer = null;

}

}

好了,一个简单的小例子就介绍到这里,做完了感觉很简单,但是说实话,对于我这种android新手还是花了不少时间才搞懂的。

 

你可能感兴趣的:(简单实现音量对话框小尝试)