简体   繁体   中英

Conditionally consume MotionEvents

public class CalendarEventView extends LinearLayout {
public CalendarEventView(Context context) {
    super(context);
}

public CalendarEventView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CalendarEventView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);

    if((event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP)  && event.getAction() != MotionEvent.ACTION_MOVE){
        Log.v("move", "click");
        return true;
    }

    return false;
}
}

I have 2 viewpagers which I synchronise. One contains CalendarEventViews. They were staying synchronised until I added onClick and onLongClick to my CalendarEventView (I set these listeners in the viewpager).

My problem is that I can only get either clicks working or scroll working, but not both. In other words how do I let my CalendarEventView consume clicks but let its parent handle movement/scrolling.

Note: I don't mind if both the CalendarEventView and the parent (viewpager) are able to handle the event as long as they both receive it.

Try this :

long eventStarted;
long threshold = 500; //500ms
@Override
public boolean onTouchEvent(MotionEvent event) {
  super.onTouchEvent(event);
  switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      eventStarted = System.currentTimeMillis();
      Log.v("move", "action down");
      return (true);
    case MotionEvent.ACTION_MOVE:
      return (System.currentTimeMillis() > (eventStarted + threshold));
    case MotionEvent.ACTION_UP:
      if (System.currentTimeMillis() <= (eventStarted + threshold)) {
        //This is a click
      }
      eventStarted = 0;
      return (true);
  }
  return false;
}

Basically you change the default OnClickListener to implement your version, so that you don't consume the move events.

ViewGroup, which is parent, receives firstly interceptTouchEvent, and if some child returns true, then parent wouldn't receive other events.

Basically, you could always return false, and react on click, if it's actually click event. Dragging is detected via treshold

So I couldn't solve it, but I found an alternative. I looked at how I was synchronising my viewpagers and found an alternative that doesn't need to use touch events. My custom view above is no longer needed. Just in case it is useful to somebody:

        // Synchronise both ViewPagers
//        headerColumnViewPager.setOnTouchListener(new OnTouchListener() {
//            @Override
//            public boolean onTouch(View v, MotionEvent event) {
//                contentColumnViewPager.onTouchEvent(event);
//                return false;
//            }
//        });
//        contentColumnViewPager.setOnTouchListener(new OnTouchListener() {
//            @Override
//            public boolean onTouch(View v, MotionEvent event) {
//                headerColumnViewPager.onTouchEvent(event);
//                return false;
//            }
//        });

    headerColumnViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        private int mScrollState = ViewPager.SCROLL_STATE_IDLE;

        @Override
        public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
                return;
            }
            contentColumnViewPager.scrollTo(headerColumnViewPager.getScrollX(), contentColumnViewPager.getScrollY());
        }

        @Override
        public void onPageSelected(final int position) { }

        @Override
        public void onPageScrollStateChanged(final int state) {
            mScrollState = state;
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                contentColumnViewPager.setCurrentItem(headerColumnViewPager.getCurrentItem(), false);
            }
        }
    });

    contentColumnViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        private int mScrollState = ViewPager.SCROLL_STATE_IDLE;

        @Override
        public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
                return;
            }
            headerColumnViewPager.scrollTo(contentColumnViewPager.getScrollX(), headerColumnViewPager.getScrollY());
        }

        @Override
        public void onPageSelected(final int position) { }

        @Override
        public void onPageScrollStateChanged(final int state) {
            mScrollState = state;
            if (state == ViewPager.SCROLL_STATE_IDLE) {
                headerColumnViewPager.setCurrentItem(contentColumnViewPager.getCurrentItem(), false);
            }
        }
    });

Source: Synchronizing two ViewPagers using OnPageChangeListener

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM