平台:Android2.3
场景:Hifi播放器,使用原生的SeekBar进行音量的调节,是一种音量骤变的效果(从50点到200,50->200值的跳变)。这样的用户体验有些糟糕。所以客户需求,调节音量时,当值的设定跨度很大时,采用平滑渐进的设定方式,即50,52,54,,,,200.
时间:2011.11.15
前提:
1.采用了定制组件+Apk响应的实现方式
2.需求主要分为:
1).音量平滑设定。对于音量的控制由底层提供接口,在SeekBar中的调节,只需要对应上每次setProgress()设定的值即可。在Apk中,重载SeekBar的onProgressChanged()函数时,进行设定即可。
2).SeekBar的平滑滚动修改
3.SeekBar继承与AbsSeekBar,修改相关两个核心函数:负责UI刷新的onProgressRefresh(),负责交互的trackTouchEvent(),其中的setProgress()调用是修改切入点。
具体思路,截断trackTouchEvent()中setProgress()的调用,增加一个定时器来分解值的设定。同时由于涉及到UI的更新,需要通过Handler来协助处理,否则可能造成主线程的阻塞。
修改:
private boolean WISKY_DEBUG = true;
private String TAG = "SeekBar";
private static int refreshTime = 50; //执行频率(ms)
private final MySeekBar mySeekbar = this;
private static int absValue = 0; //控制刷新次数
private Timer timer;
private Handler h = null;
private Message message = null;
private static final int INVALIDATE = 1;
private static int mRefershFlag; //刷新标志----1,递增。0,递减.
private boolean isFinished = false; //是否完成移动操作
private boolean isTimerOn = false; //定时器是否开启
private static final int volume_level = 18; //音量设置单步长度
h = new Handler(){
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
switch(msg.what) {
case INVALIDATE:
TimerRunner();
break;
default:
break;
}
super.handleMessage(msg);
}
};
private void setTimer(){
isFinished = false;
isTimerOn = true;
if(timer == null){
timer = new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
if (null == message) {
message = new Message();
} else {
message = Message.obtain();
}
message.what = INVALIDATE;
h.sendMessage(message);
//absValue--; //次数递减
absValue = absValue - volume_level;
if(absValue <= 0 ){
cancelTimer();
}
}}, 0, refreshTime);
}
}
private void cancelTimer(){
if(timer != null){
timer.cancel();
timer = null;
}
isFinished = true;
isTimerOn = false;
}
private void TimerRunner(){
int curProgress = getProgress();
if(WISKY_DEBUG) Log.i(TAG, "My__TimerRunner()______enter curProgress is " + String.valueOf(curProgress));
if(mRefershFlag == 1){ //递增
curProgress = curProgress + volume_level;
mySeekbar.setProgress(curProgress, true);
}
else{ //递减
curProgress = curProgress - volume_level;
mySeekbar.setProgress(curProgress, true);
}
}
private void trackTouchEvent(MotionEvent event) {
...
// setProgress((int) progress, true);
absValue = Math.abs(getProgress() - (int)progress);
//单次移动大于24时,启动timer进行自动滑动
if(absValue > 24){
if(WISKY_DEBUG) Log.i(TAG, "My__trackTouchEvent()__enter____________my if_______absValue is " + String.valueOf(absValue));
if(getProgress() >= (int)progress){
mRefershFlag = 0; //之前的比现在的大---递减
}
else{
mRefershFlag = 1; //递增
}
setTimer();
}
else{
if(WISKY_DEBUG) Log.i(TAG, "My__trackTouchEvent()__enter____________else______________________________________");
if(timer == null){ //定时器已经释放掉---定时器存在时,不让进行设置progress
setProgress((int) progress, true);
}
}
}
public boolean getisTimerOn(){
return isTimerOn;
}
public boolean getisFinished(){
return isFinished;
}
public void setisFinished(boolean isfinished){
isFinished = isfinished;
}
经过上面对SeekBar的重写后,在Apk中调用进行相关的配合调用即可。
后话:时间太久远,好不容易看懂自己乱七八糟的代码。当时真的是为了实现功能而实现,后续没有任何整理。代码也是脏乱差。-_-!!!
整个实现的代码link:链接:http://pan.baidu.com/s/1dDxrcOh 密码:disx