我正在创建一个MP3播放器并想要一个双下一首歌曲/快进按钮。因此,如果按下此按钮,它将继续播放到下一首歌曲,如果按下它,它将快进当前歌曲。
我可以使用OnClickListener让下一首歌工作......
private OnClickListener mSkipForwardListener = new OnClickListener() {
public void onClick(View v)
{
mPlayerService.forwardASong();
}
};
...但我如何获得快进功能?我尝试过OnLongClickListener,但只触发一次。
private OnLongClickListener mFastForwardListener = new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mPlayerService.fastForward();
return true;
}
};
onTouch似乎只在key.down和key.up上触发一次。
private OnTouchListener mFastForwardListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mPlayerService.fastForward();
return true;
}
};
任何帮助,非常感谢, 微米。
答案 0 :(得分:6)
从true
返回onTouch
,您正在使用触摸事件,因此您的按钮甚至看不到它。不再发生触摸事件的原因是没有View实际处理了down事件。
因此,您需要在听众中从false
返回onTouch
。 (并希望底层视图不断返回true
,因为如果在这种情况下的View - 按钮 - 从它的onTouchEvent
返回false,那么也不会再向侦听器发送任何事件 - 对于一个按钮,这是很好,但是对于其他视图覆盖onTouchEvent
而不是使用监听器来获得更多控制和可靠性。)
类似下面的OnTouchListener
应该大致正确(这需要是一个Activity的内部类,并且不要设置OnClickListener
,因为它也会被调用!) :
private abstract class LongTouchActionListener implements OnTouchListener {
/**
* Implement these methods in classes that extend this
*/
public abstract void onClick(View v);
public abstract void onLongTouchAction(View v);
/**
* The time before we count the current touch as
* a long touch
*/
public static final long LONG_TOUCH_TIME = 500;
/**
* The interval before calling another action when the
* users finger is held down
*/
public static final long LONG_TOUCH_ACTION_INTERVAL = 100;
/**
* The time the user first put their finger down
*/
private long mTouchDownTime;
/**
* The coordinates of the first touch
*/
private float mTouchDownX;
private float mTouchDownY;
/**
* The amount the users finger has to move in DIPs
* before we cancel the touch event
*/
public static final int TOUCH_MOVE_LIMIT_DP = 50;
/**
* TOUCH_MOVE_LIMIT_DP converted to pixels, and squared
*/
private float mTouchMoveLimitPxSq;
/**
* Is the current touch event a long touch event
*/
private boolean mIsLongTouch;
/**
* Is the current touch event a simple quick tap (click)
*/
private boolean mIsClick;
/**
* Handlers to post UI events
*/
private LongTouchHandler mHandler;
/**
* Reference to the long-touched view
*/
private View mLongTouchView;
/**
* Constructor
*/
public LongTouchActionListener(Context context) {
final float scale = context.getResources().getDisplayMetrics().density;
mTouchMoveLimitPxSq = scale*scale*TOUCH_MOVE_LIMIT_DP*TOUCH_MOVE_LIMIT_DP;
mHandler = new LongTouchHandler();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// down event
mIsLongTouch = false;
mIsClick = true;
mTouchDownX = event.getX();
mTouchDownY = event.getY();
mTouchDownTime = event.getEventTime();
mLongTouchView = view;
// post a runnable
mHandler.setEmptyMessageDelayed(LongTouchHandler.MESSAGE_LONG_TOUCH_WAIT, LONG_TOUCH_TIME);
break;
case MotionEvent.ACTION_MOVE:
// check to see if the user has moved their
// finger too far
if (mIsClick || mIsLongTouch) {
final float xDist = (event.getX() - mTouchDownX);
final float yDist = (event.getY() - mTouchDownY);
final float distanceSq = (xDist*xDist) + (yDist*yDist);
if (distanceSq > mTouchMoveLimitSqPx) {
// cancel the current operation
mHandler.removeMessages(LongTouchHandler.MESSAGE_LONG_TOUCH_WAIT);
mHandler.removeMessages(LongTouchHandler.MESSAGE_LONG_TOUCH_ACTION);
mIsClick = false;
mIsLongTouch = false;
}
}
break;
case MotionEvent.ACTION_CANCEL:
mIsClick = false;
case MotionEvent.ACTION_UP:
// cancel any message
mHandler.removeMessages(LongTouchHandler.MESSAGE_LONG_TOUCH_WAIT);
mHandler.removeMessages(LongTouchHandler.MESSAGE_LONG_TOUCH_ACTION);
long elapsedTime = event.getEventTime() - mTouchDownTime;
if (mIsClick && elapsedTime < LONG_TOUCH_TIME) {
onClick(v);
}
break;
}
// we did not consume the event, pass it on
// to the button
return false;
}
/**
* Handler to run actions on UI thread
*/
private class LongTouchHandler extends Handler {
public static final int MESSAGE_LONG_TOUCH_WAIT = 1;
public static final int MESSAGE_LONG_TOUCH_ACTION = 2;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_LONG_TOUCH_WAIT:
mIsLongTouch = true;
mIsClick = false;
// flow into next case
case MESSAGE_LONG_TOUCH_ACTION:
if (!mIsLongTouch) return;
onLongTouchAction(mLongTouchView); // call users function
// wait for a bit then update
takeNapThenUpdate();
break;
}
}
private void takeNapThenUpdate() {
sendEmptyMessageDelayed(MESSAGE_LONG_TOUCH_ACTION, LONG_TOUCH_ACTION_INTERVAL);
}
};
};
这是一个实现的例子
private class FastForwardTouchListener extends LongTouchActionListener {
public void onClick(View v) {
// Next track
}
public void onLongTouchAction(View v) {
// Fast forward the amount of time
// between long touch action calls
mPlayer.seekTo(mPlayer.getCurrentPosition() + LONG_TOUCH_ACTION_INTERVAL);
}
}
答案 1 :(得分:2)
受上面建议的代码的启发,你可以使用Activity的Message Handler让一个或多个按钮定期连续执行它的动作,但是以比上面建议更简单的方式(不引入私有的抽象扩展类) 。在短按期间进行不同的动作比在连续按压期间做的更简单,与我在下面显示的内容略有不同。
在按钮初始化中,实现onClick和onTouch方法:
myButton = (Button) findViewById(R.id.MyButton);
myButton.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View arg0) {
Log.i("myBtn", "Clicked ");
// perform click / short press action
}
}
);
myButton.setOnTouchListener(
new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i("myBtn", "Btn Down");
v.performClick(); // call the above onClick handler now if appropriate
// Make this a repeating button, using MessageHandler
Message msg = new Message();
msg.what = MESSAGE_CHECK_BTN_STILL_PRESSED;
msg.arg1 = R.id.MyButton;
msg.arg2 = 250; // this btn's repeat time in ms
v.setTag(v); // mark btn as pressed (any non-null)
myGuiHandler.sendMessageDelayed(msg, msg.arg2);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
v.setTag(null); // mark btn as not pressed
break;
}
return true; // return true to prevent calling btn onClick handler
}
}
);
活动的消息处理程序可能是:
public static final int MESSAGE_CHECK_BTN_STILL_PRESSED = 1;
public final Handler myGuiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_CHECK_BTN_STILL_PRESSED:
Button btn = (Button) findViewById(msg.arg1);
if (btn.getTag() != null) { // button is still pressed
Log.i("myBtn", "still pressed");
btn.performClick(); // perform Click or different long press action
Message msg1 = new Message(); // schedule next btn pressed check
msg1.copyFrom(msg);
myGuiHandler.sendMessageDelayed(msg1, msg1.arg2);
}
break;
}
}
};