如何使用双短按连续按钮实现按钮?

时间:2011-05-06 23:05:34

标签: android button onclick ontouchlistener

我正在创建一个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;
    }
};

任何帮助,非常感谢, 微米。

2 个答案:

答案 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;
        } 
    }
};