Home | History | Annotate | Download | only in deskclock
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.deskclock;
     18 
     19 import android.content.Context;
     20 import android.support.v4.view.ViewConfigurationCompat;
     21 import android.support.v4.view.ViewPager;
     22 import android.util.AttributeSet;
     23 import android.view.MotionEvent;
     24 import android.view.View;
     25 import android.view.ViewConfiguration;
     26 import android.view.ViewParent;
     27 
     28 public class VerticalViewPager extends ViewPager {
     29     // TODO Remove the hack of using a parent view pager
     30     private ViewPager mParentViewPager;
     31     private float mLastMotionX;
     32     private float mLastMotionY;
     33     private float mTouchSlop;
     34     private boolean mVerticalDrag;
     35     private boolean mHorizontalDrag;
     36 
     37     // Vertical transit page transformer
     38     private final ViewPager.PageTransformer mPageTransformer = new ViewPager.PageTransformer() {
     39         @Override
     40         public void transformPage(View view, float position) {
     41             final int pageWidth = view.getWidth();
     42             final int pageHeight = view.getHeight();
     43             if (position < -1) {
     44                 // This page is way off-screen to the left.
     45                 view.setAlpha(0);
     46             } else if (position <= 1) {
     47                 view.setAlpha(1);
     48                 // Counteract the default slide transition
     49                 view.setTranslationX(pageWidth * -position);
     50                 // set Y position to swipe in from top
     51                 float yPosition = position * pageHeight;
     52                 view.setTranslationY(yPosition);
     53             } else {
     54                 // This page is way off-screen to the right.
     55                 view.setAlpha(0);
     56             }
     57         }
     58     };
     59 
     60     public VerticalViewPager(Context context) {
     61         super(context, null);
     62     }
     63 
     64     public VerticalViewPager(Context context, AttributeSet attrs) {
     65         super(context, attrs);
     66         final ViewConfiguration configuration = ViewConfiguration.get(context);
     67         mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
     68         init();
     69     }
     70 
     71     private void init() {
     72         // Make page transit vertical
     73         setPageTransformer(true, mPageTransformer);
     74         // Get rid of the overscroll drawing that happens on the left and right (the ripple)
     75         setOverScrollMode(View.OVER_SCROLL_NEVER);
     76     }
     77 
     78     @Override
     79     public boolean onTouchEvent(MotionEvent ev) {
     80         try {
     81             initializeParent();
     82             final float x = ev.getX();
     83             final float y = ev.getY();
     84             switch (ev.getAction()) {
     85                 case MotionEvent.ACTION_DOWN: {
     86                     mLastMotionX = x;
     87                     mLastMotionY = y;
     88                     if (!mParentViewPager.onTouchEvent(ev))
     89                         return false;
     90                     return verticalDrag(ev);
     91                 }
     92                 case MotionEvent.ACTION_MOVE: {
     93                     final float xDiff = Math.abs(x - mLastMotionX);
     94                     final float yDiff = Math.abs(y - mLastMotionY);
     95                     if (!mHorizontalDrag && !mVerticalDrag) {
     96                         if (xDiff > mTouchSlop && xDiff > yDiff) { // Swiping left and right
     97                             mHorizontalDrag = true;
     98                         } else if (yDiff > mTouchSlop && yDiff > xDiff) { //Swiping up and down
     99                             mVerticalDrag = true;
    100                         }
    101                     }
    102                     if (mHorizontalDrag) {
    103                         return mParentViewPager.onTouchEvent(ev);
    104                     } else if (mVerticalDrag) {
    105                         return verticalDrag(ev);
    106                     }
    107                 }
    108                 case MotionEvent.ACTION_UP: {
    109                     if (mHorizontalDrag) {
    110                         mHorizontalDrag = false;
    111                         return mParentViewPager.onTouchEvent(ev);
    112                     }
    113                     if (mVerticalDrag) {
    114                         mVerticalDrag = false;
    115                         return verticalDrag(ev);
    116                     }
    117                 }
    118             }
    119             // Set both flags to false in case user lifted finger in the parent view pager
    120             mHorizontalDrag = false;
    121             mVerticalDrag = false;
    122         } catch (Exception e) {
    123             // The mParentViewPager shouldn't be null, but just in case. If this happens,
    124             // app should not crash, instead just ignore the user swipe input
    125             // TODO: handle the exception gracefully
    126         }
    127         return false;
    128     }
    129 
    130     private void initializeParent() {
    131         if (mParentViewPager == null) {
    132             // This vertical view pager is nested in the frame layout inside the timer tab
    133             // (fragment), which is nested inside the horizontal view pager. Therefore,
    134             // it needs 3 layers to get all the way to the horizontal view pager.
    135             final ViewParent parent = getParent().getParent().getParent();
    136             if (parent instanceof ViewPager) {
    137                 mParentViewPager = (ViewPager) parent;
    138             }
    139         }
    140     }
    141 
    142     private boolean verticalDrag(MotionEvent ev) {
    143         final float x = ev.getX();
    144         final float y = ev.getY();
    145         ev.setLocation(y, x);
    146         return super.onTouchEvent(ev);
    147     }
    148 }
    149