检测自定义视图的长按?

时间:2016-01-08 06:10:08

标签: android android-view android-custom-view

我有一个扩展FrameLayout并实现ScaleGestureDetector.OnScaleGestureListener的自定义视图。正如类名所示,此视图是可缩放的+可扩展的。继承人自定义视图类:https://gist.github.com/Orbyt/23c82ce9002df6c318d4

我一直试图找到一种方法来检测此视图的长按。我知道,通常,我可以在Activity中执行类似的操作:

GestureDetector mGestureDetector = new GestureDetector(this, this);

        mZoomableLayout.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return mGestureDetector.onTouchEvent(event);
            }
        });

        mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {

            @Override
            public void onLongPress(MotionEvent e) {
                // do tasks here
            }
        });

使用它,View不再可缩放,可能是因为它拦截了所有onTouch事件而不是Views类中的实现。

所以我的问题是,在这个视图中检测长按的最简洁方法是什么?

3 个答案:

答案 0 :(得分:2)

首先,您需要使用触摸坡度来区分实际移动和无意的用户手指移动(请参阅ACTION_MOVE)。其次,如果您要延长FrameLayout,则覆盖onTouchEvent代替this.setOnTouchListener中的init()更清晰。

将变量添加到自定义视图中:

private final Handler mHandler = new Handler();
private ScaleGestureDetector mScaleDetector;
private int mTouchSlop;
private Runnable mLongPressed = new Runnable() {
    public void run() {
        Log.i(TAG, "Long press!");
        //Do your long press stuff here.
    }
};

内部init()

mScaleDetector = new ScaleGestureDetector(context, this);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

在switch语句中:

switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        //Whatever you were doing previously here
        mHandler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout());
        break;
    case MotionEvent.ACTION_MOVE:
        if (mode == Mode.DRAG) {
            dx = motionEvent.getX() - startX;
            dy = motionEvent.getY() - startY;
            if(Math.abs(dx) > mTouchSlop || Math.abs(dy) > mTouchSlop) {
                //Actual movement
                mHandler.removeCallbacks(mLongPressed);
            } else {
                //Below touch slop, not a movement
                dx = 0;
                dy = 0;
            }
        }
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        mHandler.removeCallbacks(mLongPressed);
        //Whatever you were doing previously here
        break;
    case MotionEvent.ACTION_POINTER_UP:
        mHandler.removeCallbacks(mLongPressed);
        //Whatever you were doing previously here
        break;
    case MotionEvent.ACTION_UP:
        mHandler.removeCallbacks(mLongPressed);
        //Whatever you were doing previously here
        break;
}
//Whatever you were doing previously here

现在所有三个功能都在运作。

如果需要长按点,请创建一个抽象类,使用浮点x和y实现Runnable并将其填入ACTION_DOWN,然后使用run()中的坐标

答案 1 :(得分:2)

我有一个缩放变焦圈,我在其上检测到正常点击和长按。下面给出了代码片段。在这里,我检测到MotionEvent.ACTION_DOWN和MotionEvent.ACTION_UP之间的时间间隔长按和正常点击。

愿这对你有所帮助。

     private static final int MAX_CLICK_DURATION = 200;
     private float mScaleFactor = 1.0000000f;
     private long mStartClickTime;


     @Override
     public boolean onTouchEvent(MotionEvent event) {
     float x = event.getX();
     float y = event.getY();
     boolean right = x > (screenWidthPX / 2 + ((mLayoutHeight / 4) + 20) * mScaleFactor);
     boolean left = x < (screenWidthPX / 2 - ((mLayoutHeight / 4) + 20) * mScaleFactor);
     boolean top = y > (mLayoutHeight / 2 + ((mLayoutHeight / 4) + 20) * mScaleFactor);
     boolean bottom = y < (mLayoutHeight / 2 - ((mLayoutHeight / 4) + 20) * mScaleFactor);


     if (event.getPointerCount() > 1) {
        if (left || right || top || bottom) {
            //  You may not need this condtion, I needed this because I had custom view of pinch zoom circle and, this condition detects the touch at outer area of circle.             
        } else {
            mScaleGestureDetector.onTouchEvent(event);
        }
     } else {
        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN: {
                mStartClickTime = Calendar.getInstance().getTimeInMillis();

                break;
            }
            case MotionEvent.ACTION_UP: {
                long clickDuration = Calendar.getInstance().getTimeInMillis() - mStartClickTime;

                if (clickDuration < MAX_CLICK_DURATION) {
                    if (left || right || top || bottom) {

                    } else {
                        Toast.makeText(mContext, "Normal CLick Detected", Toast.LENGTH_SHORT).show();
                    }
                 } else {
                    Toast.makeText(mContext, "Long CLick Detected", Toast.LENGTH_SHORT).show();

                }
            }
        }
    }
    return true;
}

答案 2 :(得分:1)

好的,对不起,我根本不了解你的问题。 现在进入您的MainActivity:

public yourMainConstructor()
{
  [...]

  GestureDetector sgd;
  sgd = new GestureDetector(context,new ScaleListener());

  [...]
}

class ScaleListener extends GestureDetector.SimpleOnGestureListener {

    @Override
    public void onLongPress(MotionEvent e) {

        super.onLongPress(e);
    }
}

然后在主类onTouchEvent()

中覆盖
@Override
public boolean onTouchEvent(MotionEvent event) 
{
    sgd.onTouchEvent(event);

    switch (event.getAction()) 
    {
        case MotionEvent.ACTION_DOWN:
        [...]
    }
}