如何检测onTouch侦听器中的单击?

时间:2013-07-24 10:28:46

标签: java android android-viewpager

ViewPager内有ScrollView。我需要能够水平滚动以及垂直滚动。为了达到这个目的,只要触摸ViewPagerv.getParent().requestDisallowInterceptTouchEvent(true);),就必须禁用垂直滚动,以便可以水平滚动。

但与此同时,我需要能够点击viewPager以全屏模式打开它。

问题是onTouch在onClick之前被调用,我的OnClick永远不会被调用。

如何实现触摸onClick?

viewPager.setOnTouchListener(new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        System.out.println("TOUCHED ");
        if(event.getAction() == MotionEvent.???){
            //open fullscreen activity
        }
        v.getParent().requestDisallowInterceptTouchEvent(true); //This cannot be removed
        return false;
    }
});

viewPager.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        System.out.println("CLICKED ");
        Intent fullPhotoIntent = new Intent(context, FullPhotoActivity.class);
        fullPhotoIntent.putStringArrayListExtra("imageUrls", imageUrls);
        startActivity(fullPhotoIntent);
    }
});

12 个答案:

答案 0 :(得分:57)

Masoud Dadashi的回答帮助我解决了问题。

这是它最终的样子。

viewPager.setOnTouchListener(new OnTouchListener() {
    private int CLICK_ACTION_THRESHOLD = 200;
    private float startX;
    private float startY;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = event.getX();
            startY = event.getY();
            break;
        case MotionEvent.ACTION_UP: 
            float endX = event.getX();
            float endY = event.getY();
            if (isAClick(startX, endX, startY, endY)) { 
                launchFullPhotoActivity(imageUrls);// WE HAVE A CLICK!!
            }
            break;
        }
        v.getParent().requestDisallowInterceptTouchEvent(true); //specific to my project
        return false; //specific to my project
    }

    private boolean isAClick(float startX, float endX, float startY, float endY) {
        float differenceX = Math.abs(startX - endX);
        float differenceY = Math.abs(startY - endY);
        return !(differenceX > CLICK_ACTION_THRESHOLD/* =5 */ || differenceY > CLICK_ACTION_THRESHOLD);
    } 
}

答案 1 :(得分:20)

我通过记录用户触摸屏幕的时间来做一些非常简单的事情。

julia> typeof(2 ^ 3 ^ 4)
Int64

另外值得注意的是GestureDetector内置了这个内容。请看onSingleTapUp

答案 2 :(得分:9)

发展两者是错误的想法。当用户通过触摸屏幕来做不同的事情时,了解用户的目的有点漂亮,你需要为它开发一段代码。

两种解决方案:

onTouch事件中的

1-(更好的主意)检查是否有动作。您可以通过使用以下方法检查是否有任何移动来执行此操作:

ACTION_UP
ACTION_DOWN
ACTION_MOVE

这样做

if(event.getAction() != MotionEvent.ACTION_MOVE)

您甚至可以检查用户手指在屏幕上移动的距离,以确保发生移动而不是在点击时意外移动。这样做:

switch(event.getAction())
 {
     case MotionEvent.ACTION_DOWN:
              if(isDown == false)
              {
                     startX = event.getX();
                     startY = event.getY();
                     isDown = true;
              }
              Break;
        case MotionEvent.ACTION_UP
              {
                     endX = event.getX();
                     endY = event.getY();
                     break;
          }
}

如果上述情况均未发生,请将其视为点击,并执行您想要执行的操作。

2)如果使用您的UI进行设置,请创建按钮或图像按钮或任何其他内容进行全面筛选,并为其设置onClick。

祝你好运

答案 3 :(得分:5)

您可能需要区分用户点击和长按。否则,你会发现两者都是同一个东西。我这样做是为了使这成为可能:

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        startX = event.getX();
        startY = event.getY();

        bClick = true;
        tmrClick = new Timer();
        tmrClick.schedule(new TimerTask() {
            public void run() {
                if (bClick == true) {
                    bClick = false;
                    Log.d(LOG_TAG, "Hey, a long press event!");
                    //Handle the longpress event.
                }
            }
        }, 500); //500ms is the standard longpress response time. Adjust as you see fit.

        return true;
    case MotionEvent.ACTION_UP:
        endX = event.getX();
        endY = event.getY();

        diffX = Math.abs(startX - endX);
        diffY = Math.abs(startY - endY);

        if (diffX <= 5 && diffY <= 5 && bClick == true) {
            Log.d(LOG_TAG, "A click event!");
            bClick = false;
        }
        return true;
    default:
        return false;
    }
}

答案 4 :(得分:4)

上面的答案主要是记住时间。但是,MotionEvent已经覆盖了您。这是开销较小的解决方案。它用kotlin编写,但仍然应该可以理解:

private const val ClickThreshold = 100

override fun onTouch(v: View, event: MotionEvent): Boolean {
    if(event.action == MotionEvent.ACTION_UP 
      && event.eventTime - event.downTime < ClickThreshold) {
        v.performClick()
        return true // If you don't want to do any more actions
    }

    // do something in case its not a click

    return true // or false, whatever you need here
}

此解决方案对于大多数应用程序来说已经足够好,但是在区分单击和快速滑动之间却不是那么好。

因此,将其与上面的答案(也考虑到该职位)相结合,可能是最好的选择。

答案 5 :(得分:2)

我认为组合的解决方案时间/位置应该更好:

 private float initialTouchX;
 private float initialTouchY;
 private long lastTouchDown;
 private static int CLICK_ACTION_THRESHHOLD = 100;
 @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        lastTouchDown = System.currentTimeMillis();

                        //get the touch location
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        int Xdiff = (int) (event.getRawX() - initialTouchX);
                        int Ydiff = (int) (event.getRawY() - initialTouchY);

                        if (System.currentTimeMillis() - lastTouchDown < CLICK_ACTION_THRESHHOLD &&  (Xdiff < 10 && Ydiff < 10))  {
                           //clicked!!!
                        }
                        return true;
                }
                return false;
            }
        });

答案 6 :(得分:2)

优雅的方式

class DetailedReportTable(tables.Table):
    ...

    class Meta:
        row_attrs = { "bg-color": lambda record: "#8B0000" if record['Warning'] else "#000000" }

答案 7 :(得分:0)

我相信您阻止视图以这种方式接收触摸事件,因为您的TouchListener会拦截它。 你可以

  • 通过调用v.onTouchEvent(event)
  • 在ToucheListener中发送活动
  • 覆盖ViewPager.onTouchEvent(MotionEvent)而不是拦截事件

此外,返回true表示您没有使用该事件,并且您不会对以下事件感兴趣,因此在手势完成之前您不会收到以下事件(即手指又起来了。)

答案 8 :(得分:0)

您可以使用OnTouchClickListener

https://github.com/hoffergg/BaseLibrary/blob/master/src/main/java/com/dailycation/base/view/listener/OnTouchClickListener.java

用法:

view.setOnTouchListener(new OnTouchClickListener(new OnTouchClickListener.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //perform onClick
                }
            },5));

答案 9 :(得分:0)

if (event.eventTime - event.downTime < 100 && event.actionMasked == MotionEvent.ACTION_UP) {
     view.performClick()
     return false
}

答案 10 :(得分:0)

此代码将同时执行触摸事件和点击事件。

viewPager.setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;


            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        //remember the initial position.
                        initialX = params.x;
                        initialY = params.y;

                        //get the touch location
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        int Xdiff = (int) (event.getRawX() - initialTouchX);
                        int Ydiff = (int) (event.getRawY() - initialTouchY);


                        //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.
                        
                        if (Xdiff < 10 && Ydiff < 10) {
                            //So that is click event.
                        }
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        //Calculate the X and Y coordinates of the view.
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);


                        //Update the layout with new X & Y coordinate
                        mWindowManager.updateViewLayout(mFloatingView, params);
                        return true;
                }
                return false;
            }
        });

这是source.

答案 11 :(得分:-1)

我认为你的问题来自这条线:

v.getParent().requestDisallowInterceptTouchEvent(true); //This cannot be removed

看看documentation。 你试过删除线路吗?没有删除这条线的理由是什么?

根据documentation,如果从onTouchListener返回true,则会消耗该事件,如果返回false,则传播该事件,因此您可以使用它来传播事件。 / p>

此外,您应该更改以下代码:

 System.out.println("CLICKED ");

为:

 Log.d("MyApp", "CLICKED ");

在logcat中获得正确的输出。