长按"上一首"、"下一首"按钮实现歌曲快退、快进功能,代码如下
重写按钮ImageButton,RepeatingImageButton.java
/**
* A button that will repeatedly call a 'listener' method
* as long as the button is pressed.
*/
public class RepeatingImageButton extends ImageButton {
private long mStartTime;
private int mRepeatCount;
private RepeatListener mListener;
private long mInterval = 500;
public RepeatingImageButton(Context context) {
this(context, null);
}
public RepeatingImageButton(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.imageButtonStyle);
}
public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
setLongClickable(true);
}
/**
* Sets the listener to be called while the button is pressed and
* the interval in milliseconds with which it will be called.
* @param l The listener that will be called
* @param interval The interval in milliseconds for calls
*/
public void setRepeatListener(RepeatListener l, long interval) {
mListener = l;
mInterval = interval;
}
@Override
public boolean performLongClick() {
mStartTime = SystemClock.elapsedRealtime();
mRepeatCount = 0;
post(mRepeater);
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
// remove the repeater, but call the hook one more time
removeCallbacks(mRepeater);
if (mStartTime != 0) {
doRepeat(true);
mStartTime = 0;
}
}
return super.onTouchEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
// need to call super to make long press work, but return
// true so that the application doesn't get the down event.
super.onKeyDown(keyCode, event);
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
// remove the repeater, but call the hook one more time
removeCallbacks(mRepeater);
if (mStartTime != 0) {
doRepeat(true);
mStartTime = 0;
}
}
return super.onKeyUp(keyCode, event);
}
private Runnable mRepeater = new Runnable() {
public void run() {
doRepeat(false);
if (isPressed()) {
postDelayed(this, mInterval);
}
}
};
private void doRepeat(boolean last) {
long now = SystemClock.elapsedRealtime();
if (mListener != null) {
mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
}
}
public interface RepeatListener {
/**
* This method will be called repeatedly at roughly the interval
* specified in setRepeatListener(), for as long as the button
* is pressed.
* @param v The button as a View.
* @param duration The number of milliseconds the button has been pressed so far.
* @param repeatcount The number of previous calls in this sequence.
* If this is going to be the last call in this sequence (i.e. the user
* just stopped pressing the button), the value will be -1.
*/
void onRepeat(View v, long duration, int repeatcount);
}
}
MediaPlaybackActivity.java中的代码如下:
mNextButton = (RepeatingImageButton) findViewById(R.id.next);
mNextButton.setOnClickListener(mNextListener);
mNextButton.setRepeatListener(mFfwdListener, 260);
private RepeatingImageButton.RepeatListener mFfwdListener =
new RepeatingImageButton.RepeatListener() {
public void onRepeat(View v, long howlong, int repcnt) {
scanForward(repcnt, howlong);
}
};
private void scanForward(int repcnt, long delta) {
if(mService == null) return;
try {
if(repcnt == 0) {
mStartSeekPos = mService.position();
mLastSeekEventTime = 0;
mSeeking = false;
} else {
mSeeking = true;
if (delta < 5000) {
// seek at 10x speed for the first 5 seconds
delta = delta * 10;
} else {
// seek at 40x after that
delta = 50000 + (delta - 5000) * 40;
}
long newpos = mStartSeekPos + delta;
long duration = mService.duration();
if (newpos >= duration) {
// move to next track
mService.next();
mStartSeekPos -= duration; // is OK to go negative
newpos -= duration;
}
if (((delta - mLastSeekEventTime) > 250) || repcnt < 0){
mService.seek(newpos);
mLastSeekEventTime = delta;
}
if (repcnt >= 0) {
mPosOverride = newpos;
} else {
mPosOverride = -1;
}
refreshNow();
}
} catch (RemoteException ex) {
}
}
mPrevButton = (RepeatingImageButton) findViewById(R.id.prev);
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setRepeatListener(mRewListener, 260);
private RepeatingImageButton.RepeatListener mRewListener =
new RepeatingImageButton.RepeatListener() {
public void onRepeat(View v, long howlong, int repcnt) {
scanBackward(repcnt, howlong);
}
};
private void scanBackward(int repcnt, long delta) {
if(mService == null) return;
try {
if(repcnt == 0) {
mStartSeekPos = mService.position();
mLastSeekEventTime = 0;
mSeeking = false;
} else {
mSeeking = true;
if (delta < 5000) {
// seek at 10x speed for the first 5 seconds
delta = delta * 10;
} else {
// seek at 40x after that
delta = 50000 + (delta - 5000) * 40;
}
long newpos = mStartSeekPos - delta;
if (newpos < 0) {
// move to previous track
mService.prev();
long duration = mService.duration();
mStartSeekPos += duration;
newpos += duration;
}
if (((delta - mLastSeekEventTime) > 250) || repcnt < 0){
mService.seek(newpos);
mLastSeekEventTime = delta;
}
if (repcnt >= 0) {
mPosOverride = newpos;
} else {
mPosOverride = -1;
}
refreshNow();
}
} catch (RemoteException ex) {
}
}