android - 如何实现双短按和长按的Button?

标签 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;
    }
};

任何帮助,非常感谢,

最佳答案

通过从 onTouch 返回 true,您正在使用触摸事件,因此您的按钮甚至看不到它。不再发生触摸事件的原因是没有 View 实际处理了按下事件。

因此您需要在监听器中从 onTouch 返回 false。 (并希望底层 View 继续返回 true,因为如果 View - 在这种情况下的按钮 - 从它的 onTouchEvent 返回 false,那么也不会再有事件发送给您的监听器- 对于一个按钮,这很好,但对于其他 View ,覆盖 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);
    }
}

关于android - 如何实现双短按和长按的Button?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5917909/

相关文章:

javascript - 使用javascript在div中通过标签选择元素

Android - 在 mipmap 与 drawable 文件夹中存储图像

android - 将字符 "©"插入到我的 json 对象的任何属性中会破坏我的 php 代码

java - Gradle任务assembleDebug失败,退出代码为1 ERROR?

javascript - 可以链接图像映射以打开浏览文件 Controller 吗?

android - 在 sleep 状态下长按音量按钮(android)

java - 如何告诉 ProGuard 保留私有(private)字段而不指定每个字段

html - 改变按钮的大小

javascript - 将 img 直接路径 src 传递给输入 onClick

javascript - 从导航点击切换类内容