package com.github.jjobes.slidedaytimepicker; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.NumberPicker; import android.widget.TimePicker; /** * A custom {@link android.support.v4.view.ViewPager} implementation that corrects * the height of the ViewPager and also dispatches touch events to either the ViewPager * or the day or time picker depending on the direction of the swipe. * * @author jjobes * */ public class CustomViewPager extends ViewPager { private NumberPicker mDayPicker; private TimePicker mTimePicker; private float x1, y1, x2, y2; private float mTouchSlop; public CustomViewPager(Context context) { super(context); init(context); } public CustomViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context) { mTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop(); } /** * Setting wrap_content on a ViewPager's layout_height in XML * doesn't seem to be recognized and the ViewPager will fill the * height of the screen regardless. We'll force the ViewPager to * have the same height as its immediate child. */ @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (getChildCount() > 0) { View childView = getChildAt(0); if (childView != null) { childView.measure(widthMeasureSpec, heightMeasureSpec); int h = childView.getMeasuredHeight(); setMeasuredDimension(getMeasuredWidth(), h); getLayoutParams().height = h; } } mDayPicker = (NumberPicker) findViewById(R.id.dayPicker); mTimePicker = (TimePicker) findViewById(R.id.timePicker); } /** * When the user swipes their finger horizontally, dispatch * those touch events to the ViewPager. When they swipe * vertically, dispatch those touch events to the day or * time picker (depending on which page we're currently on). * * @param event */ @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: x1 = event.getX(); y1 = event.getY(); break; case MotionEvent.ACTION_MOVE: x2 = event.getX(); y2 = event.getY(); if (isScrollingHorizontal(x1, y1, x2, y2)) { // When the user is scrolling the ViewPager horizontally, // block the pickers from scrolling vertically. return super.dispatchTouchEvent(event); } break; } // As long as the ViewPager isn't scrolling horizontally, // dispatch the event to the NumberPicker or TimePicker, // depending on which page the ViewPager is currently on. switch (getCurrentItem()) { case 0: if (mDayPicker != null) mDayPicker.dispatchTouchEvent(event); break; case 1: if (mTimePicker != null) mTimePicker.dispatchTouchEvent(event); break; } // need this for the ViewPager to scroll horizontally at all return super.onTouchEvent(event); } /** * Determine whether the distance between the user's ACTION_DOWN * event (x1, y1) and the current ACTION_MOVE event (x2, y2) should * be interpreted as a horizontal swipe. * * @param x1 * @param y1 * @param x2 * @param y2 * @return */ private boolean isScrollingHorizontal(float x1, float y1, float x2, float y2) { float deltaX = x2 - x1; float deltaY = y2 - y1; if (Math.abs(deltaX) > mTouchSlop && Math.abs(deltaX) > Math.abs(deltaY)) { return true; } return false; } }