Search code examples
androidclickswipetouch-eventgesturedetector

How to handle touch event for child view in parent view


I'm making a custom calendar view which extends LinearLayout and has child views for each date. What I want to do is handling swipe and click, as you can imagine, swipe is for changing month and click is for selecting a date and showing new activity. To do this, I use GestureDetector on CalendarView and could make it work for swipe. But to handle click event, I have no idea how to find a child view which click happened.

  1. Does anyone have any idea to resolve this?
  2. What's the difference between return true and false on OnScroll(MotionEvent)?

Below is part of my codes.

public class MonthView extends LinearLayout implements GestureDetector.OnGestureListener {

    public MonthView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        gestureDetector = new GestureDetector(this);
        initDateViews();
    }

    //other codes here
    ....

    private void initDateViews() {
        for(int i = 0; i < 42; i++) {
            DateView view = new DateView();
            //init date views and add to calendar view.
            ....
            calendar.Add(view);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Logger.debug(TAG, ">>> MonthView.onTouchEvent()");

        return gestureDetector.onTouchEvent(event);
    }

    @Override
    public boolean OnSingleTapUp(MotionEvent event) {
        // how can I find a child view to handle click event?
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        // right to left
        if (e1.getX() - e2.getX() > minSwipeDistance) {
            this.prevMonth();
        }
        // left to right
        else if(e2.getX() - e1.getX() > minSwipeDistance) {
            this.nextMonth();
        }
        // bottom to top
        else if(e1.getY() - e2.getY() > minSwipeDistance) {
            this.prevMonth();
        }
        //top to bottom
        else if(e2.getY() - e1.getY() > minSwipeDistance) {
            this.nextMonth();
        }

        return false;
    }

    ....
}

Solution

  • I resolved this by overriding 'onInterceptTouchEvent()' on MonthView, and posting the solution to help someone who would struggle with same issue. I implemented GestureDetector to change month on 'onFling()' like below codes.

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean result = gestureDetector.onTouchEvent(event);
    
        return result;
    }
    
    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }
    
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // right to left
        if (e1.getX() - e2.getX() > minSwipeDistance) {
            nextMonth();
        }
        // left to right
        else if(e2.getX() - e1.getX() > minSwipeDistance) {
            prevMonth();
        }
        // bottom to top
        else if(e1.getY() - e2.getY() > minSwipeDistance) {
            nextMonth();
        }
        //top to bottom
        else if(e2.getY() - e1.getY() > minSwipeDistance) {
            prevMonth();
        }
    
        return true;
    }
    
    @Override
    public void onLongPress(MotionEvent e) {
    }
    
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }
    
    @Override
    public void onShowPress(MotionEvent e) {
    }
    
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }