垂直翻页的Viewpager 兼容华为手机

转自:http://blog.csdn.net/yymonkeydo/article/details/47012153

在github中找到了一个可以垂直翻页的ViewPager,但是只能使用的是他写的pagerAdapter的子类,为了,让自己的项目中也可以使用v4和v13的适配器,自己就改动了一点点,代码如下:

[java]  view plain  copy
 print ?
  1. package com.yymonkeydo.androiddemo;  
  2.   
  3. import java.lang.reflect.Method;  
  4. import java.util.ArrayList;  
  5. import java.util.Collections;  
  6. import java.util.Comparator;  
  7.   
  8. import android.content.Context;  
  9. import android.content.res.TypedArray;  
  10. import android.database.DataSetObserver;  
  11. import android.graphics.Canvas;  
  12. import android.graphics.Rect;  
  13. import android.graphics.drawable.Drawable;  
  14. import android.os.Build;  
  15. import android.os.Bundle;  
  16. import android.os.Parcel;  
  17. import android.os.Parcelable;  
  18. import android.os.SystemClock;  
  19. import android.support.v4.os.ParcelableCompat;  
  20. import android.support.v4.os.ParcelableCompatCreatorCallbacks;  
  21. import android.support.v4.view.AccessibilityDelegateCompat;  
  22. import android.support.v4.view.KeyEventCompat;  
  23. import android.support.v4.view.MotionEventCompat;  
  24. import android.support.v4.view.PagerAdapter;  
  25. import android.support.v4.view.VelocityTrackerCompat;  
  26. import android.support.v4.view.ViewCompat;  
  27. import android.support.v4.view.ViewConfigurationCompat;  
  28. import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;  
  29. import android.support.v4.widget.EdgeEffectCompat;  
  30. import android.util.AttributeSet;  
  31. import android.util.FloatMath;  
  32. import android.util.Log;  
  33. import android.view.FocusFinder;  
  34. import android.view.Gravity;  
  35. import android.view.KeyEvent;  
  36. import android.view.MotionEvent;  
  37. import android.view.SoundEffectConstants;  
  38. import android.view.VelocityTracker;  
  39. import android.view.View;  
  40. import android.view.ViewConfiguration;  
  41. import android.view.ViewGroup;  
  42. import android.view.ViewParent;  
  43. import android.view.accessibility.AccessibilityEvent;  
  44. import android.view.animation.Interpolator;  
  45. import android.widget.Scroller;  
  46.   
  47. /** 
  48.  * Layout manager that allows the user to flip left and right through pages of 
  49.  * data. You supply an implementation of a {@link PagerAdapter} to generate the 
  50.  * pages that the view shows. 
  51.  *  
  52.  * <p> 
  53.  * Note this class is currently under early design and development. The API will 
  54.  * likely change in later updates of the compatibility library, requiring 
  55.  * changes to the source code of apps when they are compiled against the newer 
  56.  * version. 
  57.  * </p> 
  58.  *  
  59.  * <p> 
  60.  * ViewPager is most often used in conjunction with {@link android.app.Fragment} 
  61.  * , which is a convenient way to supply and manage the lifecycle of each page. 
  62.  * There are standard adapters implemented for using fragments with the 
  63.  * ViewPager, which cover the most common use cases. These are 
  64.  * {@link android.support.v4.app.FragmentPagerAdapter}, 
  65.  * {@link android.support.v4.app.FragmentStatePagerAdapter}, 
  66.  * {@link android.support.v13.app.FragmentPagerAdapter}, and 
  67.  * {@link android.support.v13.app.FragmentStatePagerAdapter}; each of these 
  68.  * classes have simple code showing how to build a full user interface with 
  69.  * them. 
  70.  *  
  71.  * <p> 
  72.  * Here is a more complicated example of ViewPager, using it in conjuction with 
  73.  * {@link android.app.ActionBar} tabs. You can find other examples of using 
  74.  * ViewPager in the API 4+ Support Demos and API 13+ Support Demos sample code. 
  75.  *  
  76.  * {@sample 
  77.  * development/samples/Support13Demos/src/com/example/android/supportv13/app/ 
  78.  * ActionBarTabsPager.java complete} 
  79.  */  
  80. public class VerticalViewPager extends ViewGroup {  
  81.     private static final String TAG = "VerticalViewPager";  
  82.     private static final boolean DEBUG = false;  
  83.   
  84.     private static final boolean USE_CACHE = false;  
  85.   
  86.     private static final int DEFAULT_OFFSCREEN_PAGES = 1;  
  87.     private static final int MAX_SETTLE_DURATION = 600// ms  
  88.     private static final int MIN_DISTANCE_FOR_FLING = 25// dips  
  89.   
  90.     private static final int DEFAULT_GUTTER_SIZE = 16// dips  
  91.   
  92.     private static final int[] LAYOUT_ATTRS = new int[] { android.R.attr.layout_gravity };  
  93.   
  94.     static class ItemInfo {  
  95.         Object object;  
  96.         int position;  
  97.         boolean scrolling;  
  98.         float widthFactor;  
  99.         float heightFactor;  
  100.         float offset;  
  101.     }  
  102.   
  103.     private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>() {  
  104.         @Override  
  105.         public int compare(ItemInfo lhs, ItemInfo rhs) {  
  106.             return lhs.position - rhs.position;  
  107.         }  
  108.     };  
  109.   
  110.     private static final Interpolator sInterpolator = new Interpolator() {  
  111.         public float getInterpolation(float t) {  
  112.             t -= 1.0f;  
  113.             return t * t * t * t * t + 1.0f;  
  114.         }  
  115.     };  
  116.   
  117.     private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();  
  118.     private final ItemInfo mTempItem = new ItemInfo();  
  119.   
  120.     private final Rect mTempRect = new Rect();  
  121.   
  122.     private PagerAdapter mAdapter;  
  123.     private int mCurItem; // Index of currently displayed page.  
  124.     private int mRestoredCurItem = -1;  
  125.     private Parcelable mRestoredAdapterState = null;  
  126.     private ClassLoader mRestoredClassLoader = null;  
  127.     private Scroller mScroller;  
  128.     private PagerObserver mObserver;  
  129.   
  130.     private int mPageMargin;  
  131.     private Drawable mMarginDrawable;  
  132.     private int mLeftPageBounds;  
  133.     private int mRightPageBounds;  
  134.   
  135.     // Offsets of the first and last items, if known.  
  136.     // Set during population, used to determine if we are at the beginning  
  137.     // or end of the pager data set during touch scrolling.  
  138.     private float mFirstOffset = -Float.MAX_VALUE;  
  139.     private float mLastOffset = Float.MAX_VALUE;  
  140.   
  141.     private int mChildWidthMeasureSpec;  
  142.     private boolean mInLayout;  
  143.   
  144.     private boolean mScrollingCacheEnabled;  
  145.   
  146.     private boolean mPopulatePending;  
  147.     private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;  
  148.   
  149.     private boolean mIsBeingDragged;  
  150.     private boolean mIsUnableToDrag;  
  151.     private int mDefaultGutterSize;  
  152.     private int mGutterSize;  
  153.     private int mTouchSlop;  
  154.     private float mInitialMotionX;  
  155.     private float mInitialMotionY;  
  156.     /** 
  157.      * Position of the last motion event. 
  158.      */  
  159.     private float mLastMotionX;  
  160.     private float mLastMotionY;  
  161.     /** 
  162.      * ID of the active pointer. This is used to retain consistency during 
  163.      * drags/flings if multiple pointers are used. 
  164.      */  
  165.     private int mActivePointerId = INVALID_POINTER;  
  166.     /** 
  167.      * Sentinel value for no current active pointer. Used by 
  168.      * {@link #mActivePointerId}. 
  169.      */  
  170.     private static final int INVALID_POINTER = -1;  
  171.   
  172.     /** 
  173.      * Determines speed during touch scrolling 
  174.      */  
  175.     private VelocityTracker mVelocityTracker;  
  176.     private int mMinimumVelocity;  
  177.     private int mMaximumVelocity;  
  178.     private int mFlingDistance;  
  179.     private int mCloseEnough;  
  180.     private int mSeenPositionMin;  
  181.     private int mSeenPositionMax;  
  182.   
  183.     // If the pager is at least this close to its final position, complete the  
  184.     // scroll  
  185.     // on touch down and let the user interact with the content inside instead  
  186.     // of  
  187.     // "catching" the flinging pager.  
  188.     private static final int CLOSE_ENOUGH = 2// dp  
  189.   
  190.     private boolean mFakeDragging;  
  191.     private long mFakeDragBeginTime;  
  192.   
  193.     private EdgeEffectCompat mTopEdge;  
  194.     private EdgeEffectCompat mBottomEdge;  
  195.   
  196.     private boolean mFirstLayout = true;  
  197.     private boolean mCalledSuper;  
  198.     private int mDecorChildCount;  
  199.   
  200.     private OnPageChangeListener mOnPageChangeListener;  
  201.     private OnPageChangeListener mInternalPageChangeListener;  
  202.     private OnAdapterChangeListener mAdapterChangeListener;  
  203.     private PageTransformer mPageTransformer;  
  204.     private Method mSetChildrenDrawingOrderEnabled;  
  205.   
  206.     private static final int DRAW_ORDER_DEFAULT = 0;  
  207.     private static final int DRAW_ORDER_FORWARD = 1;  
  208.     private static final int DRAW_ORDER_REVERSE = 2;  
  209.     private int mDrawingOrder;  
  210.     private ArrayList<View> mDrawingOrderedChildren;  
  211.     private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator();  
  212.   
  213.     /** 
  214.      * Indicates that the pager is in an idle, settled state. The current page 
  215.      * is fully in view and no animation is in progress. 
  216.      */  
  217.     public static final int SCROLL_STATE_IDLE = 0;  
  218.   
  219.     /** 
  220.      * Indicates that the pager is currently being dragged by the user. 
  221.      */  
  222.     public static final int SCROLL_STATE_DRAGGING = 1;  
  223.   
  224.     /** 
  225.      * Indicates that the pager is in the process of settling to a final 
  226.      * position. 
  227.      */  
  228.     public static final int SCROLL_STATE_SETTLING = 2;  
  229.   
  230.     private final Runnable mEndScrollRunnable = new Runnable() {  
  231.         public void run() {  
  232.             setScrollState(SCROLL_STATE_IDLE);  
  233.             populate();  
  234.         }  
  235.     };  
  236.   
  237.     private int mScrollState = SCROLL_STATE_IDLE;  
  238.   
  239.     /** 
  240.      * Callback interface for responding to changing state of the selected page. 
  241.      */  
  242.     public interface OnPageChangeListener {  
  243.   
  244.         /** 
  245.          * This method will be invoked when the current page is scrolled, either 
  246.          * as part of a programmatically initiated smooth scroll or a user 
  247.          * initiated touch scroll. 
  248.          *  
  249.          * @param position 
  250.          *            Position index of the first page currently being 
  251.          *            displayed. Page position+1 will be visible if 
  252.          *            positionOffset is nonzero. 
  253.          * @param positionOffset 
  254.          *            Value from [0, 1) indicating the offset from the page at 
  255.          *            position. 
  256.          * @param positionOffsetPixels 
  257.          *            Value in pixels indicating the offset from position. 
  258.          */  
  259.         public void onPageScrolled(int position, float positionOffset,  
  260.                 int positionOffsetPixels);  
  261.   
  262.         /** 
  263.          * This method will be invoked when a new page becomes selected. 
  264.          * Animation is not necessarily complete. 
  265.          *  
  266.          * @param position 
  267.          *            Position index of the new selected page. 
  268.          */  
  269.         public void onPageSelected(int position);  
  270.   
  271.         /** 
  272.          * Called when the scroll state changes. Useful for discovering when the 
  273.          * user begins dragging, when the pager is automatically settling to the 
  274.          * current page, or when it is fully stopped/idle. 
  275.          *  
  276.          * @param state 
  277.          *            The new scroll state. 
  278.          * @see VerticalViewPager#SCROLL_STATE_IDLE 
  279.          * @see VerticalViewPager#SCROLL_STATE_DRAGGING 
  280.          * @see VerticalViewPager#SCROLL_STATE_SETTLING 
  281.          */  
  282.         public void onPageScrollStateChanged(int state);  
  283.     }  
  284.   
  285.     /** 
  286.      * Simple implementation of the {@link OnPageChangeListener} interface with 
  287.      * stub implementations of each method. Extend this if you do not intend to 
  288.      * override every method of {@link OnPageChangeListener}. 
  289.      */  
  290.     public static class SimpleOnPageChangeListener implements  
  291.             OnPageChangeListener {  
  292.         @Override  
  293.         public void onPageScrolled(int position, float positionOffset,  
  294.                 int positionOffsetPixels) {  
  295.             // This space for rent  
  296.         }  
  297.   
  298.         @Override  
  299.         public void onPageSelected(int position) {  
  300.             // This space for rent  
  301.         }  
  302.   
  303.         @Override  
  304.         public void onPageScrollStateChanged(int state) {  
  305.             // This space for rent  
  306.         }  
  307.     }  
  308.   
  309.     /** 
  310.      * A PageTransformer is invoked whenever a visible/attached page is 
  311.      * scrolled. This offers an opportunity for the application to apply a 
  312.      * custom transformation to the page views using animation properties. 
  313.      *  
  314.      * <p> 
  315.      * As property animation is only supported as of Android 3.0 and forward, 
  316.      * setting a PageTransformer on a ViewPager on earlier platform versions 
  317.      * will be ignored. 
  318.      * </p> 
  319.      */  
  320.     public interface PageTransformer {  
  321.         /** 
  322.          * Apply a property transformation to the given page. 
  323.          *  
  324.          * @param page 
  325.          *            Apply the transformation to this page 
  326.          * @param position 
  327.          *            Position of page relative to the current front-and-center 
  328.          *            position of the pager. 0 is front and center. 1 is one 
  329.          *            full page position to the right, and -1 is one page 
  330.          *            position to the left. 
  331.          */  
  332.         public void transformPage(View page, float position);  
  333.     }  
  334.   
  335.     /** 
  336.      * Used internally to monitor when adapters are switched. 
  337.      */  
  338.     interface OnAdapterChangeListener {  
  339.         public void onAdapterChanged(PagerAdapter oldAdapter,  
  340.                 PagerAdapter newAdapter);  
  341.     }  
  342.   
  343.     /** 
  344.      * Used internally to tag special types of child views that should be added 
  345.      * as pager decorations by default. 
  346.      */  
  347.     interface Decor {  
  348.     }  
  349.   
  350.     public VerticalViewPager(Context context) {  
  351.         super(context);  
  352.         initViewPager();  
  353.     }  
  354.   
  355.     public VerticalViewPager(Context context, AttributeSet attrs) {  
  356.         super(context, attrs);  
  357.         initViewPager();  
  358.     }  
  359.   
  360.     void initViewPager() {  
  361.         setWillNotDraw(false);  
  362.         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);  
  363.         setFocusable(true);  
  364.         final Context context = getContext();  
  365.         mScroller = new Scroller(context, sInterpolator);  
  366.         final ViewConfiguration configuration = ViewConfiguration.get(context);  
  367.         mTouchSlop = ViewConfigurationCompat  
  368.                 .getScaledPagingTouchSlop(configuration);  
  369.         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();  
  370.         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();  
  371.   
  372.         mTopEdge = new EdgeEffectCompat(context);  
  373.         mBottomEdge = new EdgeEffectCompat(context);  
  374.   
  375.         final float density = context.getResources().getDisplayMetrics().density;  
  376.         mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);  
  377.         mCloseEnough = (int) (CLOSE_ENOUGH * density);  
  378.         mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);  
  379.   
  380.         ViewCompat  
  381.                 .setAccessibilityDelegate(thisnew MyAccessibilityDelegate());  
  382.   
  383.         if (ViewCompat.getImportantForAccessibility(this) == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {  
  384.             ViewCompat.setImportantForAccessibility(this,  
  385.                     ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);  
  386.         }  
  387.     }  
  388.   
  389.     @Override  
  390.     protected void onDetachedFromWindow() {  
  391.         removeCallbacks(mEndScrollRunnable);  
  392.         super.onDetachedFromWindow();  
  393.     }  
  394.   
  395.     private void setScrollState(int newState) {  
  396.         if (mScrollState == newState) {  
  397.             return;  
  398.         }  
  399.   
  400.         mScrollState = newState;  
  401.         if (newState == SCROLL_STATE_DRAGGING) {  
  402.             mSeenPositionMin = mSeenPositionMax = -1;  
  403.         }  
  404.         if (mPageTransformer != null) {  
  405.             // PageTransformers can do complex things that benefit from hardware  
  406.             // layers.  
  407.             enableLayers(newState != SCROLL_STATE_IDLE);  
  408.         }  
  409.         if (mOnPageChangeListener != null) {  
  410.             mOnPageChangeListener.onPageScrollStateChanged(newState);  
  411.         }  
  412.     }  
  413.   
  414.     /** 
  415.      * Set a PagerAdapter that will supply views for this pager as needed. 
  416.      *  
  417.      * @param adapter 
  418.      *            Adapter to use 
  419.      */  
  420.     public void setAdapter(PagerAdapter adapter) {  
  421.         if (mAdapter != null) {  
  422.             mAdapter.unregisterDataSetObserver(mObserver);  
  423.             mAdapter.startUpdate(this);  
  424.             for (int i = 0; i < mItems.size(); i++) {  
  425.                 final ItemInfo ii = mItems.get(i);  
  426.                 mAdapter.destroyItem(this, ii.position, ii.object);  
  427.             }  
  428.             mAdapter.finishUpdate(this);  
  429.             mItems.clear();  
  430.             removeNonDecorViews();  
  431.             mCurItem = 0;  
  432.             scrollTo(00);  
  433.         }  
  434.   
  435.         final PagerAdapter oldAdapter = mAdapter;  
  436.         mAdapter = adapter;  
  437.   
  438.         if (mAdapter != null) {  
  439.             if (mObserver == null) {  
  440.                 mObserver = new PagerObserver();  
  441.             }  
  442.             mAdapter.registerDataSetObserver(mObserver);  
  443.             mPopulatePending = false;  
  444.             mFirstLayout = true;  
  445.             if (mRestoredCurItem >= 0) {  
  446.                 mAdapter.restoreState(mRestoredAdapterState,  
  447.                         mRestoredClassLoader);  
  448.                 setCurrentItemInternal(mRestoredCurItem, falsetrue);  
  449.                 mRestoredCurItem = -1;  
  450.                 mRestoredAdapterState = null;  
  451.                 mRestoredClassLoader = null;  
  452.             } else {  
  453.                 populate();  
  454.             }  
  455.         }  
  456.   
  457.         if (mAdapterChangeListener != null && oldAdapter != adapter) {  
  458.             mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);  
  459.         }  
  460.     }  
  461.   
  462.     private void removeNonDecorViews() {  
  463.         for (int i = 0; i < getChildCount(); i++) {  
  464.             final View child = getChildAt(i);  
  465.             final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  466.             if (!lp.isDecor) {  
  467.                 removeViewAt(i);  
  468.                 i--;  
  469.             }  
  470.         }  
  471.     }  
  472.   
  473.     /** 
  474.      * Retrieve the current adapter supplying pages. 
  475.      *  
  476.      * @return The currently registered PagerAdapter 
  477.      */  
  478.     public PagerAdapter getAdapter() {  
  479.         return mAdapter;  
  480.     }  
  481.   
  482.     void setOnAdapterChangeListener(OnAdapterChangeListener listener) {  
  483.         mAdapterChangeListener = listener;  
  484.     }  
  485.   
  486.     /** 
  487.      * Set the currently selected page. If the ViewPager has already been 
  488.      * through its first layout with its current adapter there will be a smooth 
  489.      * animated transition between the current item and the specified item. 
  490.      *  
  491.      * @param item 
  492.      *            Item index to select 
  493.      */  
  494.     public void setCurrentItem(int item) {  
  495.         mPopulatePending = false;  
  496.         setCurrentItemInternal(item, !mFirstLayout, false);  
  497.     }  
  498.   
  499.     /** 
  500.      * Set the currently selected page. 
  501.      *  
  502.      * @param item 
  503.      *            Item index to select 
  504.      * @param smoothScroll 
  505.      *            True to smoothly scroll to the new item, false to transition 
  506.      *            immediately 
  507.      */  
  508.     public void setCurrentItem(int item, boolean smoothScroll) {  
  509.         mPopulatePending = false;  
  510.         setCurrentItemInternal(item, smoothScroll, false);  
  511.     }  
  512.   
  513.     public int getCurrentItem() {  
  514.         return mCurItem;  
  515.     }  
  516.   
  517.     void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {  
  518.         setCurrentItemInternal(item, smoothScroll, always, 0);  
  519.     }  
  520.   
  521.     void setCurrentItemInternal(int item, boolean smoothScroll, boolean always,  
  522.             int velocity) {  
  523.         if (mAdapter == null || mAdapter.getCount() <= 0) {  
  524.             setScrollingCacheEnabled(false);  
  525.             return;  
  526.         }  
  527.         if (!always && mCurItem == item && mItems.size() != 0) {  
  528.             setScrollingCacheEnabled(false);  
  529.             return;  
  530.         }  
  531.   
  532.         if (item < 0) {  
  533.             item = 0;  
  534.         } else if (item >= mAdapter.getCount()) {  
  535.             item = mAdapter.getCount() - 1;  
  536.         }  
  537.         final int pageLimit = mOffscreenPageLimit;  
  538.         if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {  
  539.             // We are doing a jump by more than one page. To avoid  
  540.             // glitches, we want to keep all current pages in the view  
  541.             // until the scroll ends.  
  542.             for (int i = 0; i < mItems.size(); i++) {  
  543.                 mItems.get(i).scrolling = true;  
  544.             }  
  545.         }  
  546.         final boolean dispatchSelected = mCurItem != item;  
  547.         populate(item);  
  548.         scrollToItem(item, smoothScroll, velocity, dispatchSelected);  
  549.     }  
  550.   
  551.     private void scrollToItem(int item, boolean smoothScroll, int velocity,  
  552.             boolean dispatchSelected) {  
  553.         final ItemInfo curInfo = infoForPosition(item);  
  554.         int destY = 0;  
  555.         if (curInfo != null) {  
  556.             final int height = getHeight();  
  557.             destY = (int) (height * Math.max(mFirstOffset,  
  558.                     Math.min(curInfo.offset, mLastOffset)));  
  559.         }  
  560.         if (smoothScroll) {  
  561.             smoothScrollTo(0, destY, velocity);  
  562.   
  563.             if (dispatchSelected && mOnPageChangeListener != null) {  
  564.                 mOnPageChangeListener.onPageSelected(item);  
  565.             }  
  566.             if (dispatchSelected && mInternalPageChangeListener != null) {  
  567.                 mInternalPageChangeListener.onPageSelected(item);  
  568.             }  
  569.         } else {  
  570.             if (dispatchSelected && mOnPageChangeListener != null) {  
  571.                 mOnPageChangeListener.onPageSelected(item);  
  572.             }  
  573.             if (dispatchSelected && mInternalPageChangeListener != null) {  
  574.                 mInternalPageChangeListener.onPageSelected(item);  
  575.             }  
  576.             completeScroll(false);  
  577.             scrollTo(0, destY);  
  578.         }  
  579.     }  
  580.   
  581.     /** 
  582.      * Set a listener that will be invoked whenever the page changes or is 
  583.      * incrementally scrolled. See {@link OnPageChangeListener}. 
  584.      *  
  585.      * @param listener 
  586.      *            Listener to set 
  587.      */  
  588.     public void setOnPageChangeListener(OnPageChangeListener listener) {  
  589.         mOnPageChangeListener = listener;  
  590.     }  
  591.   
  592.     /** 
  593.      * Set a {@link PageTransformer} that will be called for each attached page 
  594.      * whenever the scroll position is changed. This allows the application to 
  595.      * apply custom property transformations to each page, overriding the 
  596.      * default sliding look and feel. 
  597.      *  
  598.      * <p> 
  599.      * <em>Note:</em> Prior to Android 3.0 the property animation APIs did not 
  600.      * exist. As a result, setting a PageTransformer prior to Android 3.0 (API 
  601.      * 11) will have no effect. 
  602.      * </p> 
  603.      *  
  604.      * @param reverseDrawingOrder 
  605.      *            true if the supplied PageTransformer requires page views to be 
  606.      *            drawn from last to first instead of first to last. 
  607.      * @param transformer 
  608.      *            PageTransformer that will modify each page's animation 
  609.      *            properties 
  610.      */  
  611.     public void setPageTransformer(boolean reverseDrawingOrder,  
  612.             PageTransformer transformer) {  
  613.         if (Build.VERSION.SDK_INT >= 11) {  
  614.             final boolean hasTransformer = transformer != null;  
  615.             final boolean needsPopulate = hasTransformer != (mPageTransformer != null);  
  616.             mPageTransformer = transformer;  
  617.             setChildrenDrawingOrderEnabledCompat(hasTransformer);  
  618.             if (hasTransformer) {  
  619.                 mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE  
  620.                         : DRAW_ORDER_FORWARD;  
  621.             } else {  
  622.                 mDrawingOrder = DRAW_ORDER_DEFAULT;  
  623.             }  
  624.             if (needsPopulate)  
  625.                 populate();  
  626.         }  
  627.     }  
  628.   
  629.     void setChildrenDrawingOrderEnabledCompat(boolean enable) {  
  630.         if (mSetChildrenDrawingOrderEnabled == null) {  
  631.             try {  
  632.                 mSetChildrenDrawingOrderEnabled = ViewGroup.class  
  633.                         .getDeclaredMethod("setChildrenDrawingOrderEnabled",  
  634.                                 new Class[] { Boolean.TYPE });  
  635.             } catch (NoSuchMethodException e) {  
  636.                 Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e);  
  637.             }  
  638.         }  
  639.         try {  
  640.             mSetChildrenDrawingOrderEnabled.invoke(this, enable);  
  641.         } catch (Exception e) {  
  642.             Log.e(TAG, "Error changing children drawing order", e);  
  643.         }  
  644.     }  
  645.   
  646.     @Override  
  647.     protected int getChildDrawingOrder(int childCount, int i) {  
  648.         final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1  
  649.                 - i : i;  
  650.         final int result = ((LayoutParams) mDrawingOrderedChildren.get(index)  
  651.                 .getLayoutParams()).childIndex;  
  652.         return result;  
  653.     }  
  654.   
  655.     /** 
  656.      * Set a separate OnPageChangeListener for internal use by the support 
  657.      * library. 
  658.      *  
  659.      * @param listener 
  660.      *            Listener to set 
  661.      * @return The old listener that was set, if any. 
  662.      */  
  663.     OnPageChangeListener setInternalPageChangeListener(  
  664.             OnPageChangeListener listener) {  
  665.         OnPageChangeListener oldListener = mInternalPageChangeListener;  
  666.         mInternalPageChangeListener = listener;  
  667.         return oldListener;  
  668.     }  
  669.   
  670.     /** 
  671.      * Returns the number of pages that will be retained to either side of the 
  672.      * current page in the view hierarchy in an idle state. Defaults to 1. 
  673.      *  
  674.      * @return How many pages will be kept offscreen on either side 
  675.      * @see #setOffscreenPageLimit(int) 
  676.      */  
  677.     public int getOffscreenPageLimit() {  
  678.         return mOffscreenPageLimit;  
  679.     }  
  680.   
  681.     /** 
  682.      * Set the number of pages that should be retained to either side of the 
  683.      * current page in the view hierarchy in an idle state. Pages beyond this 
  684.      * limit will be recreated from the adapter when needed. 
  685.      *  
  686.      * <p> 
  687.      * This is offered as an optimization. If you know in advance the number of 
  688.      * pages you will need to support or have lazy-loading mechanisms in place 
  689.      * on your pages, tweaking this setting can have benefits in perceived 
  690.      * smoothness of paging animations and interaction. If you have a small 
  691.      * number of pages (3-4) that you can keep active all at once, less time 
  692.      * will be spent in layout for newly created view subtrees as the user pages 
  693.      * back and forth. 
  694.      * </p> 
  695.      *  
  696.      * <p> 
  697.      * You should keep this limit low, especially if your pages have complex 
  698.      * layouts. This setting defaults to 1. 
  699.      * </p> 
  700.      *  
  701.      * @param limit 
  702.      *            How many pages will be kept offscreen in an idle state. 
  703.      */  
  704.     public void setOffscreenPageLimit(int limit) {  
  705.         if (limit < DEFAULT_OFFSCREEN_PAGES) {  
  706.             Log.w(TAG, "Requested offscreen page limit " + limit  
  707.                     + " too small; defaulting to " + DEFAULT_OFFSCREEN_PAGES);  
  708.             limit = DEFAULT_OFFSCREEN_PAGES;  
  709.         }  
  710.         if (limit != mOffscreenPageLimit) {  
  711.             mOffscreenPageLimit = limit;  
  712.             populate();  
  713.         }  
  714.     }  
  715.   
  716.     /** 
  717.      * Set the margin between pages. 
  718.      *  
  719.      * @param marginPixels 
  720.      *            Distance between adjacent pages in pixels 
  721.      * @see #getPageMargin() 
  722.      * @see #setPageMarginDrawable(Drawable) 
  723.      * @see #setPageMarginDrawable(int) 
  724.      */  
  725.     public void setPageMargin(int marginPixels) {  
  726.         final int oldMargin = mPageMargin;  
  727.         mPageMargin = marginPixels;  
  728.   
  729.         final int width = getWidth();  
  730.         recomputeScrollPosition(width, width, marginPixels, oldMargin);  
  731.   
  732.         requestLayout();  
  733.     }  
  734.   
  735.     /** 
  736.      * Return the margin between pages. 
  737.      *  
  738.      * @return The size of the margin in pixels 
  739.      */  
  740.     public int getPageMargin() {  
  741.         return mPageMargin;  
  742.     }  
  743.   
  744.     /** 
  745.      * Set a drawable that will be used to fill the margin between pages. 
  746.      *  
  747.      * @param d 
  748.      *            Drawable to display between pages 
  749.      */  
  750.     public void setPageMarginDrawable(Drawable d) {  
  751.         mMarginDrawable = d;  
  752.         if (d != null)  
  753.             refreshDrawableState();  
  754.         setWillNotDraw(d == null);  
  755.         invalidate();  
  756.     }  
  757.   
  758.     /** 
  759.      * Set a drawable that will be used to fill the margin between pages. 
  760.      *  
  761.      * @param resId 
  762.      *            Resource ID of a drawable to display between pages 
  763.      */  
  764.     public void setPageMarginDrawable(int resId) {  
  765.         setPageMarginDrawable(getContext().getResources().getDrawable(resId));  
  766.     }  
  767.   
  768.     @Override  
  769.     protected boolean verifyDrawable(Drawable who) {  
  770.         return super.verifyDrawable(who) || who == mMarginDrawable;  
  771.     }  
  772.   
  773.     @Override  
  774.     protected void drawableStateChanged() {  
  775.         super.drawableStateChanged();  
  776.         final Drawable d = mMarginDrawable;  
  777.         if (d != null && d.isStateful()) {  
  778.             d.setState(getDrawableState());  
  779.         }  
  780.     }  
  781.   
  782.     // We want the duration of the page snap animation to be influenced by the  
  783.     // distance that  
  784.     // the screen has to travel, however, we don't want this duration to be  
  785.     // effected in a  
  786.     // purely linear fashion. Instead, we use this method to moderate the effect  
  787.     // that the distance  
  788.     // of travel has on the overall snap duration.  
  789.     float distanceInfluenceForSnapDuration(float f) {  
  790.         f -= 0.5f; // center the values about 0.  
  791.         f *= 0.3f * Math.PI / 2.0f;  
  792.         return (float) Math.sin(f);  
  793.     }  
  794.   
  795.     /** 
  796.      * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 
  797.      *  
  798.      * @param x 
  799.      *            the number of pixels to scroll by on the X axis 
  800.      * @param y 
  801.      *            the number of pixels to scroll by on the Y axis 
  802.      */  
  803.     void smoothScrollTo(int x, int y) {  
  804.         smoothScrollTo(x, y, 0);  
  805.     }  
  806.   
  807.     /** 
  808.      * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. 
  809.      *  
  810.      * @param x 
  811.      *            the number of pixels to scroll by on the X axis 
  812.      * @param y 
  813.      *            the number of pixels to scroll by on the Y axis 
  814.      * @param velocity 
  815.      *            the velocity associated with a fling, if applicable. (0 
  816.      *            otherwise) 
  817.      */  
  818.   
  819.     void smoothScrollTo(int x, int y, int velocity) {  
  820.         // void smoothScrollTo(int y, int x, int velocity) {  
  821.         if (getChildCount() == 0) {  
  822.             // Nothing to do.  
  823.             setScrollingCacheEnabled(false);  
  824.             return;  
  825.         }  
  826.   
  827.         int sx = getScrollX();  
  828.         int sy = getScrollY();  
  829.         int dx = x - sx;  
  830.         int dy = y - sy;  
  831.         if (dx == 0 && dy == 0) {  
  832.             completeScroll(false);  
  833.             populate();  
  834.             setScrollState(SCROLL_STATE_IDLE);  
  835.             return;  
  836.         }  
  837.   
  838.         setScrollingCacheEnabled(true);  
  839.         setScrollState(SCROLL_STATE_SETTLING);  
  840.   
  841.         final int height = getHeight();  
  842.         final int halfHeight = height / 2;  
  843.         final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / height);  
  844.         final float distance = halfHeight + halfHeight  
  845.                 * distanceInfluenceForSnapDuration(distanceRatio);  
  846.   
  847.         int duration = 0;  
  848.         velocity = Math.abs(velocity);  
  849.         if (velocity > 0) {  
  850.             duration = 4 * Math.round(1000 * Math.abs(distance / velocity));  
  851.         } else {  
  852.             final float pageHeight = height * mAdapter.getPageWidth(mCurItem);  
  853.             final float pageDelta = (float) Math.abs(dx)  
  854.                     / (pageHeight + mPageMargin);  
  855.             duration = (int) ((pageDelta + 1) * 100);  
  856.         }  
  857.         duration = Math.min(duration, MAX_SETTLE_DURATION);  
  858.   
  859.         mScroller.startScroll(sx, sy, dx, dy, duration);  
  860.         ViewCompat.postInvalidateOnAnimation(this);  
  861.     }  
  862.   
  863.     ItemInfo addNewItem(int position, int index) {  
  864.         ItemInfo ii = new ItemInfo();  
  865.         ii.position = position;  
  866.         ii.object = mAdapter.instantiateItem(this, position);  
  867.         ii.widthFactor = mAdapter.getPageWidth(position);  
  868.         ii.heightFactor = mAdapter.getPageWidth(position);  
  869.   
  870.         if (index < 0 || index >= mItems.size()) {  
  871.             mItems.add(ii);  
  872.         } else {  
  873.             mItems.add(index, ii);  
  874.         }  
  875.         return ii;  
  876.     }  
  877.   
  878.     void dataSetChanged() {  
  879.         // This method only gets called if our observer is attached, so mAdapter  
  880.         // is non-null.  
  881.   
  882.         boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1  
  883.                 && mItems.size() < mAdapter.getCount();  
  884.         int newCurrItem = mCurItem;  
  885.   
  886.         boolean isUpdating = false;  
  887.         for (int i = 0; i < mItems.size(); i++) {  
  888.             final ItemInfo ii = mItems.get(i);  
  889.             final int newPos = mAdapter.getItemPosition(ii.object);  
  890.   
  891.             if (newPos == PagerAdapter.POSITION_UNCHANGED) {  
  892.                 continue;  
  893.             }  
  894.   
  895.             if (newPos == PagerAdapter.POSITION_NONE) {  
  896.                 mItems.remove(i);  
  897.                 i--;  
  898.   
  899.                 if (!isUpdating) {  
  900.                     mAdapter.startUpdate(this);  
  901.                     isUpdating = true;  
  902.                 }  
  903.   
  904.                 mAdapter.destroyItem(this, ii.position, ii.object);  
  905.                 needPopulate = true;  
  906.   
  907.                 if (mCurItem == ii.position) {  
  908.                     // Keep the current item in the valid range  
  909.                     newCurrItem = Math.max(0,  
  910.                             Math.min(mCurItem, mAdapter.getCount() - 1));  
  911.                     needPopulate = true;  
  912.                 }  
  913.                 continue;  
  914.             }  
  915.   
  916.             if (ii.position != newPos) {  
  917.                 if (ii.position == mCurItem) {  
  918.                     // Our current item changed position. Follow it.  
  919.                     newCurrItem = newPos;  
  920.                 }  
  921.   
  922.                 ii.position = newPos;  
  923.                 needPopulate = true;  
  924.             }  
  925.         }  
  926.   
  927.         if (isUpdating) {  
  928.             mAdapter.finishUpdate(this);  
  929.         }  
  930.   
  931.         Collections.sort(mItems, COMPARATOR);  
  932.   
  933.         if (needPopulate) {  
  934.             // Reset our known page widths; populate will recompute them.  
  935.             final int childCount = getChildCount();  
  936.             for (int i = 0; i < childCount; i++) {  
  937.                 final View child = getChildAt(i);  
  938.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  939.                 if (!lp.isDecor) {  
  940.                     lp.widthFactor = 0.f;  
  941.                     lp.heightFactor = 0.f;  
  942.                 }  
  943.             }  
  944.   
  945.             setCurrentItemInternal(newCurrItem, falsetrue);  
  946.             requestLayout();  
  947.         }  
  948.     }  
  949.   
  950.     void populate() {  
  951.         populate(mCurItem);  
  952.     }  
  953.   
  954.     void populate(int newCurrentItem) {  
  955.         ItemInfo oldCurInfo = null;  
  956.         if (mCurItem != newCurrentItem) {  
  957.             oldCurInfo = infoForPosition(mCurItem);  
  958.             mCurItem = newCurrentItem;  
  959.         }  
  960.   
  961.         if (mAdapter == null) {  
  962.             return;  
  963.         }  
  964.   
  965.         // Bail now if we are waiting to populate. This is to hold off  
  966.         // on creating views from the time the user releases their finger to  
  967.         // fling to a new position until we have finished the scroll to  
  968.         // that position, avoiding glitches from happening at that point.  
  969.         if (mPopulatePending) {  
  970.             if (DEBUG)  
  971.                 Log.i(TAG, "populate is pending, skipping for now...");  
  972.             return;  
  973.         }  
  974.   
  975.         // Also, don't populate until we are attached to a window. This is to  
  976.         // avoid trying to populate before we have restored our view hierarchy  
  977.         // state and conflicting with what is restored.  
  978.         if (getWindowToken() == null) {  
  979.             return;  
  980.         }  
  981.   
  982.         mAdapter.startUpdate(this);  
  983.   
  984.         final int pageLimit = mOffscreenPageLimit;  
  985.         final int startPos = Math.max(0, mCurItem - pageLimit);  
  986.         final int N = mAdapter.getCount();  
  987.         final int endPos = Math.min(N - 1, mCurItem + pageLimit);  
  988.   
  989.         // Locate the currently focused item or add it if needed.  
  990.         int curIndex = -1;  
  991.         ItemInfo curItem = null;  
  992.         for (curIndex = 0; curIndex < mItems.size(); curIndex++) {  
  993.             final ItemInfo ii = mItems.get(curIndex);  
  994.             if (ii.position >= mCurItem) {  
  995.                 if (ii.position == mCurItem)  
  996.                     curItem = ii;  
  997.                 break;  
  998.             }  
  999.         }  
  1000.   
  1001.         if (curItem == null && N > 0) {  
  1002.             curItem = addNewItem(mCurItem, curIndex);  
  1003.         }  
  1004.   
  1005.         // Fill 3x the available width or up to the number of offscreen  
  1006.         // pages requested to either side, whichever is larger.  
  1007.         // If we have no current item we have no work to do.  
  1008.         if (curItem != null) {  
  1009.             float extraHeightLeft = 0f;  
  1010.             int itemIndex = curIndex - 1;  
  1011.             ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;  
  1012.             final float topHeightNeeded = 2.f - curItem.heightFactor;  
  1013.   
  1014.             for (int pos = mCurItem - 1; pos >= 0; pos--) {  
  1015.                 if (extraHeightLeft >= topHeightNeeded && pos < startPos) {  
  1016.                     if (ii == null) {  
  1017.                         break;  
  1018.                     }  
  1019.                     if (pos == ii.position && !ii.scrolling) {  
  1020.                         mItems.remove(itemIndex);  
  1021.                         mAdapter.destroyItem(this, pos, ii.object);  
  1022.                         if (DEBUG) {  
  1023.                             Log.i(TAG, "populate() - destroyItem() with pos: "  
  1024.                                     + pos + " view: " + ((View) ii.object));  
  1025.                         }  
  1026.                         itemIndex--;  
  1027.                         curIndex--;  
  1028.                         ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;  
  1029.                     }  
  1030.                 } else if (ii != null && pos == ii.position) {  
  1031.                     extraHeightLeft += ii.heightFactor;  
  1032.                     itemIndex--;  
  1033.                     ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;  
  1034.                 } else {  
  1035.                     ii = addNewItem(pos, itemIndex + 1);  
  1036.                     extraHeightLeft += ii.heightFactor;  
  1037.                     curIndex++;  
  1038.                     ii = itemIndex >= 0 ? mItems.get(itemIndex) : null;  
  1039.                 }  
  1040.             }  
  1041.   
  1042.             float extraHeightBottom = curItem.heightFactor;  
  1043.             itemIndex = curIndex + 1;  
  1044.             if (extraHeightBottom < 2.f) {  
  1045.                 ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null;  
  1046.                 for (int pos = mCurItem + 1; pos < N; pos++) {  
  1047.                     if (extraHeightBottom >= 2.f && pos > endPos) {  
  1048.                         if (ii == null) {  
  1049.                             break;  
  1050.                         }  
  1051.                         if (pos == ii.position && !ii.scrolling) {  
  1052.                             mItems.remove(itemIndex);  
  1053.                             mAdapter.destroyItem(this, pos, ii.object);  
  1054.                             if (DEBUG) {  
  1055.                                 Log.i(TAG,  
  1056.                                         "populate() - destroyItem() with pos: "  
  1057.                                                 + pos + " view: "  
  1058.                                                 + ((View) ii.object));  
  1059.                             }  
  1060.                             ii = itemIndex < mItems.size() ? mItems  
  1061.                                     .get(itemIndex) : null;  
  1062.                         }  
  1063.                     } else if (ii != null && pos == ii.position) {  
  1064.                         extraHeightBottom += ii.heightFactor;  
  1065.                         itemIndex++;  
  1066.                         ii = itemIndex < mItems.size() ? mItems.get(itemIndex)  
  1067.                                 : null;  
  1068.                     } else {  
  1069.                         ii = addNewItem(pos, itemIndex);  
  1070.                         itemIndex++;  
  1071.                         extraHeightBottom += ii.heightFactor;  
  1072.                         ii = itemIndex < mItems.size() ? mItems.get(itemIndex)  
  1073.                                 : null;  
  1074.                     }  
  1075.                 }  
  1076.             }  
  1077.   
  1078.             calculatePageOffsets(curItem, curIndex, oldCurInfo);  
  1079.         }  
  1080.   
  1081.         if (DEBUG) {  
  1082.             Log.i(TAG, "Current page list:");  
  1083.             for (int i = 0; i < mItems.size(); i++) {  
  1084.                 Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);  
  1085.             }  
  1086.         }  
  1087.   
  1088.         mAdapter.setPrimaryItem(this, mCurItem,  
  1089.                 curItem != null ? curItem.object : null);  
  1090.   
  1091.         mAdapter.finishUpdate(this);  
  1092.   
  1093.         // Check width measurement of current pages and drawing sort order.  
  1094.         // Update LayoutParams as needed.  
  1095.         final boolean sort = mDrawingOrder != DRAW_ORDER_DEFAULT;  
  1096.         if (sort) {  
  1097.             if (mDrawingOrderedChildren == null) {  
  1098.                 mDrawingOrderedChildren = new ArrayList<View>();  
  1099.             } else {  
  1100.                 mDrawingOrderedChildren.clear();  
  1101.             }  
  1102.         }  
  1103.         final int childCount = getChildCount();  
  1104.         for (int i = 0; i < childCount; i++) {  
  1105.             final View child = getChildAt(i);  
  1106.             final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1107.             lp.childIndex = i;  
  1108.             if (!lp.isDecor && lp.heightFactor == 0.f) {  
  1109.                 // 0 means requery the adapter for this, it doesn't have a valid  
  1110.                 // width.  
  1111.                 final ItemInfo ii = infoForChild(child);  
  1112.                 if (ii != null) {  
  1113.                     lp.heightFactor = ii.heightFactor;  
  1114.                     lp.position = ii.position;  
  1115.                 }  
  1116.             }  
  1117.             if (sort)  
  1118.                 mDrawingOrderedChildren.add(child);  
  1119.         }  
  1120.         if (sort) {  
  1121.             Collections.sort(mDrawingOrderedChildren, sPositionComparator);  
  1122.         }  
  1123.   
  1124.         if (hasFocus()) {  
  1125.             View currentFocused = findFocus();  
  1126.             ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused)  
  1127.                     : null;  
  1128.             if (ii == null || ii.position != mCurItem) {  
  1129.                 for (int i = 0; i < getChildCount(); i++) {  
  1130.                     View child = getChildAt(i);  
  1131.                     ii = infoForChild(child);  
  1132.                     if (ii != null && ii.position == mCurItem) {  
  1133.                         if (child.requestFocus(FOCUS_FORWARD)) {  
  1134.                             break;  
  1135.                         }  
  1136.                     }  
  1137.                 }  
  1138.             }  
  1139.         }  
  1140.     }  
  1141.   
  1142.     private void calculatePageOffsets(ItemInfo curItem, int curIndex,  
  1143.             ItemInfo oldCurInfo) {  
  1144.         final int N = mAdapter.getCount();  
  1145.         final int height = getHeight();  
  1146.   
  1147.         final float marginOffset = height > 0 ? (float) mPageMargin / height  
  1148.                 : 0;  
  1149.         // Fix up offsets for later layout.  
  1150.         if (oldCurInfo != null) {  
  1151.             final int oldCurPosition = oldCurInfo.position;  
  1152.             // Base offsets off of oldCurInfo.  
  1153.             if (oldCurPosition < curItem.position) {  
  1154.                 int itemIndex = 0;  
  1155.                 ItemInfo ii = null;  
  1156.                 float offset = oldCurInfo.offset + oldCurInfo.heightFactor  
  1157.                         + marginOffset;  
  1158.                 for (int pos = oldCurPosition + 1; pos <= curItem.position  
  1159.                         && itemIndex < mItems.size(); pos++) {  
  1160.                     ii = mItems.get(itemIndex);  
  1161.                     while (pos > ii.position && itemIndex < mItems.size() - 1) {  
  1162.                         itemIndex++;  
  1163.                         ii = mItems.get(itemIndex);  
  1164.                     }  
  1165.                     while (pos < ii.position) {  
  1166.                         // We don't have an item populated for this,  
  1167.                         // ask the adapter for an offset.  
  1168.                         offset += mAdapter.getPageWidth(pos) + marginOffset;  
  1169.                         pos++;  
  1170.                     }  
  1171.                     ii.offset = offset;  
  1172.                     offset += ii.heightFactor + marginOffset;  
  1173.                 }  
  1174.             } else if (oldCurPosition > curItem.position) {  
  1175.                 int itemIndex = mItems.size() - 1;  
  1176.                 ItemInfo ii = null;  
  1177.                 float offset = oldCurInfo.offset;  
  1178.                 for (int pos = oldCurPosition - 1; pos >= curItem.position  
  1179.                         && itemIndex >= 0; pos--) {  
  1180.                     ii = mItems.get(itemIndex);  
  1181.                     while (pos < ii.position && itemIndex > 0) {  
  1182.                         itemIndex--;  
  1183.                         ii = mItems.get(itemIndex);  
  1184.                     }  
  1185.                     while (pos > ii.position) {  
  1186.                         // We don't have an item populated for this,  
  1187.                         // ask the adapter for an offset.  
  1188.                         offset -= mAdapter.getPageWidth(pos) + marginOffset;  
  1189.                         pos--;  
  1190.                     }  
  1191.                     offset -= ii.heightFactor + marginOffset;  
  1192.                     ii.offset = offset;  
  1193.                 }  
  1194.             }  
  1195.         }  
  1196.   
  1197.         // Base all offsets off of curItem.  
  1198.         final int itemCount = mItems.size();  
  1199.         float offset = curItem.offset;  
  1200.         int pos = curItem.position - 1;  
  1201.         mFirstOffset = curItem.position == 0 ? curItem.offset  
  1202.                 : -Float.MAX_VALUE;  
  1203.         mLastOffset = curItem.position == N - 1 ? curItem.offset  
  1204.                 + curItem.heightFactor - 1 : Float.MAX_VALUE;  
  1205.         // Previous pages  
  1206.         for (int i = curIndex - 1; i >= 0; i--, pos--) {  
  1207.             final ItemInfo ii = mItems.get(i);  
  1208.             while (pos > ii.position) {  
  1209.                 offset -= mAdapter.getPageWidth(pos--) + marginOffset;  
  1210.             }  
  1211.             offset -= ii.heightFactor + marginOffset;  
  1212.             ii.offset = offset;  
  1213.             if (ii.position == 0)  
  1214.                 mFirstOffset = offset;  
  1215.         }  
  1216.         offset = curItem.offset + curItem.heightFactor + marginOffset;  
  1217.         pos = curItem.position + 1;  
  1218.         // Next pages  
  1219.         for (int i = curIndex + 1; i < itemCount; i++, pos++) {  
  1220.             final ItemInfo ii = mItems.get(i);  
  1221.             while (pos < ii.position) {  
  1222.                 offset += mAdapter.getPageWidth(pos++) + marginOffset;  
  1223.             }  
  1224.             if (ii.position == N - 1) {  
  1225.                 mLastOffset = offset + ii.heightFactor - 1;  
  1226.             }  
  1227.             ii.offset = offset;  
  1228.             offset += ii.heightFactor + marginOffset;  
  1229.         }  
  1230.   
  1231.         // mNeedCalculatePageOffsets = false;  
  1232.     }  
  1233.   
  1234.     /** 
  1235.      * This is the persistent state that is saved by ViewPager. Only needed if 
  1236.      * you are creating a sublass of ViewPager that must save its own state, in 
  1237.      * which case it should implement a subclass of this which contains that 
  1238.      * state. 
  1239.      */  
  1240.     public static class SavedState extends BaseSavedState {  
  1241.         int position;  
  1242.         Parcelable adapterState;  
  1243.         ClassLoader loader;  
  1244.   
  1245.         public SavedState(Parcelable superState) {  
  1246.             super(superState);  
  1247.         }  
  1248.   
  1249.         @Override  
  1250.         public void writeToParcel(Parcel out, int flags) {  
  1251.             super.writeToParcel(out, flags);  
  1252.             out.writeInt(position);  
  1253.             out.writeParcelable(adapterState, flags);  
  1254.         }  
  1255.   
  1256.         @Override  
  1257.         public String toString() {  
  1258.             return "FragmentPager.SavedState{"  
  1259.                     + Integer.toHexString(System.identityHashCode(this))  
  1260.                     + " position=" + position + "}";  
  1261.         }  
  1262.   
  1263.         public static final Parcelable.Creator<SavedState> CREATOR = ParcelableCompat  
  1264.                 .newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {  
  1265.                     @Override  
  1266.                     public SavedState createFromParcel(Parcel in,  
  1267.                             ClassLoader loader) {  
  1268.                         return new SavedState(in, loader);  
  1269.                     }  
  1270.   
  1271.                     @Override  
  1272.                     public SavedState[] newArray(int size) {  
  1273.                         return new SavedState[size];  
  1274.                     }  
  1275.                 });  
  1276.   
  1277.         SavedState(Parcel in, ClassLoader loader) {  
  1278.             super(in);  
  1279.             if (loader == null) {  
  1280.                 loader = getClass().getClassLoader();  
  1281.             }  
  1282.             position = in.readInt();  
  1283.             adapterState = in.readParcelable(loader);  
  1284.             this.loader = loader;  
  1285.         }  
  1286.     }  
  1287.   
  1288.     @Override  
  1289.     public Parcelable onSaveInstanceState() {  
  1290.         Parcelable superState = super.onSaveInstanceState();  
  1291.         SavedState ss = new SavedState(superState);  
  1292.         ss.position = mCurItem;  
  1293.         if (mAdapter != null) {  
  1294.             ss.adapterState = mAdapter.saveState();  
  1295.         }  
  1296.         return ss;  
  1297.     }  
  1298.   
  1299.     @Override  
  1300.     public void onRestoreInstanceState(Parcelable state) {  
  1301.         if (!(state instanceof SavedState)) {  
  1302.             super.onRestoreInstanceState(state);  
  1303.             return;  
  1304.         }  
  1305.   
  1306.         SavedState ss = (SavedState) state;  
  1307.         super.onRestoreInstanceState(ss.getSuperState());  
  1308.   
  1309.         if (mAdapter != null) {  
  1310.             mAdapter.restoreState(ss.adapterState, ss.loader);  
  1311.             setCurrentItemInternal(ss.position, falsetrue);  
  1312.         } else {  
  1313.             mRestoredCurItem = ss.position;  
  1314.             mRestoredAdapterState = ss.adapterState;  
  1315.             mRestoredClassLoader = ss.loader;  
  1316.         }  
  1317.     }  
  1318.   
  1319.     @Override  
  1320.     public void addView(View child, int index, ViewGroup.LayoutParams params) {  
  1321.         if (!checkLayoutParams(params)) {  
  1322.             params = generateLayoutParams(params);  
  1323.         }  
  1324.         final LayoutParams lp = (LayoutParams) params;  
  1325.         lp.isDecor |= child instanceof Decor;  
  1326.         if (mInLayout) {  
  1327.             if (lp != null && lp.isDecor) {  
  1328.                 throw new IllegalStateException(  
  1329.                         "Cannot add pager decor view during layout");  
  1330.             }  
  1331.             lp.needsMeasure = true;  
  1332.             addViewInLayout(child, index, params);  
  1333.         } else {  
  1334.             super.addView(child, index, params);  
  1335.         }  
  1336.   
  1337.         if (USE_CACHE) {  
  1338.             if (child.getVisibility() != GONE) {  
  1339.                 child.setDrawingCacheEnabled(mScrollingCacheEnabled);  
  1340.             } else {  
  1341.                 child.setDrawingCacheEnabled(false);  
  1342.             }  
  1343.         }  
  1344.     }  
  1345.   
  1346.     ItemInfo infoForChild(View child) {  
  1347.         for (int i = 0; i < mItems.size(); i++) {  
  1348.             ItemInfo ii = mItems.get(i);  
  1349.             if (mAdapter.isViewFromObject(child, ii.object)) {  
  1350.                 return ii;  
  1351.             }  
  1352.         }  
  1353.         return null;  
  1354.     }  
  1355.   
  1356.     ItemInfo infoForAnyChild(View child) {  
  1357.         ViewParent parent;  
  1358.         while ((parent = child.getParent()) != this) {  
  1359.             if (parent == null || !(parent instanceof View)) {  
  1360.                 return null;  
  1361.             }  
  1362.             child = (View) parent;  
  1363.         }  
  1364.         return infoForChild(child);  
  1365.     }  
  1366.   
  1367.     ItemInfo infoForPosition(int position) {  
  1368.         for (int i = 0; i < mItems.size(); i++) {  
  1369.             ItemInfo ii = mItems.get(i);  
  1370.             if (ii.position == position) {  
  1371.                 return ii;  
  1372.             }  
  1373.         }  
  1374.         return null;  
  1375.     }  
  1376.   
  1377.     @Override  
  1378.     protected void onAttachedToWindow() {  
  1379.         super.onAttachedToWindow();  
  1380.         mFirstLayout = true;  
  1381.     }  
  1382.   
  1383.     @SuppressWarnings("deprecation")  
  1384.     @Override  
  1385.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  1386.         if (DEBUG)  
  1387.             Log.d(TAG, "onMeasure");  
  1388.   
  1389.         // For simple implementation, or internal size is always 0.  
  1390.         // We depend on the container to specify the layout size of  
  1391.         // our view. We can't really know what it is since we will be  
  1392.         // adding and removing different arbitrary views and do not  
  1393.         // want the layout to change as this happens.  
  1394.         setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),  
  1395.                 getDefaultSize(0, heightMeasureSpec));  
  1396.   
  1397.         final int measuredWidth = getMeasuredWidth();  
  1398.         final int measuredHeight = getMeasuredHeight();  
  1399.   
  1400.         final int maxGutterSize = measuredHeight / 10;  
  1401.         mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize);  
  1402.   
  1403.         // Children are just made to fill our space.  
  1404.         int childWidthSize = measuredWidth - getPaddingLeft()  
  1405.                 - getPaddingRight();  
  1406.         int childHeightSize = measuredHeight - getPaddingTop()  
  1407.                 - getPaddingBottom();  
  1408.   
  1409.         /* 
  1410.          * Make sure all children have been properly measured. Decor views 
  1411.          * first. Right now we cheat and make this less complicated by assuming 
  1412.          * decor views won't intersect. We will pin to edges based on gravity. 
  1413.          */  
  1414.         int size = getChildCount();  
  1415.         for (int i = 0; i < size; ++i) {  
  1416.             final View child = getChildAt(i);  
  1417.             if (child.getVisibility() != GONE) {  
  1418.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1419.                 if (lp != null && lp.isDecor) {  
  1420.                     final int hgrav = lp.gravity  
  1421.                             & Gravity.HORIZONTAL_GRAVITY_MASK;  
  1422.                     final int vgrav = lp.gravity  
  1423.                             & Gravity.VERTICAL_GRAVITY_MASK;  
  1424.                     int widthMode = MeasureSpec.AT_MOST;  
  1425.                     int heightMode = MeasureSpec.AT_MOST;  
  1426.                     boolean consumeVertical = vgrav == Gravity.TOP  
  1427.                             || vgrav == Gravity.BOTTOM;  
  1428.                     boolean consumeHorizontal = hgrav == Gravity.LEFT  
  1429.                             || hgrav == Gravity.RIGHT;  
  1430.   
  1431.                     if (consumeVertical) {  
  1432.                         widthMode = MeasureSpec.EXACTLY;  
  1433.                     } else if (consumeHorizontal) {  
  1434.                         heightMode = MeasureSpec.EXACTLY;  
  1435.                     }  
  1436.   
  1437.                     int widthSize = childWidthSize;  
  1438.                     int heightSize = childHeightSize;  
  1439.                     if (lp.width != LayoutParams.WRAP_CONTENT) {  
  1440.                         widthMode = MeasureSpec.EXACTLY;  
  1441.                         if (lp.width != LayoutParams.FILL_PARENT) {  
  1442.                             widthSize = lp.width;  
  1443.                         }  
  1444.                     }  
  1445.                     if (lp.height != LayoutParams.WRAP_CONTENT) {  
  1446.                         heightMode = MeasureSpec.EXACTLY;  
  1447.                         if (lp.height != LayoutParams.FILL_PARENT) {  
  1448.                             heightSize = lp.height;  
  1449.                         }  
  1450.                     }  
  1451.                     final int widthSpec = MeasureSpec.makeMeasureSpec(  
  1452.                             widthSize, widthMode);  
  1453.                     final int heightSpec = MeasureSpec.makeMeasureSpec(  
  1454.                             heightSize, heightMode);  
  1455.                     child.measure(widthSpec, heightSpec);  
  1456.   
  1457.                     if (consumeVertical) {  
  1458.                         childHeightSize -= child.getMeasuredHeight();  
  1459.                     } else if (consumeHorizontal) {  
  1460.                         childWidthSize -= child.getMeasuredWidth();  
  1461.                     }  
  1462.                 }  
  1463.             }  
  1464.         }  
  1465.   
  1466.         mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize,  
  1467.                 MeasureSpec.EXACTLY);  
  1468.   
  1469.         // Make sure we have created all fragments that we need to have shown.  
  1470.         mInLayout = true;  
  1471.         populate();  
  1472.         mInLayout = false;  
  1473.   
  1474.         // Page views next.  
  1475.         size = getChildCount();  
  1476.         for (int i = 0; i < size; ++i) {  
  1477.             final View child = getChildAt(i);  
  1478.             if (child.getVisibility() != GONE) {  
  1479.                 if (DEBUG)  
  1480.                     Log.v(TAG, "Measuring #" + i + " " + child + ": "  
  1481.                             + mChildWidthMeasureSpec);  
  1482.   
  1483.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1484.                 if (lp == null || !lp.isDecor) {  
  1485.                     final int heightSpec = MeasureSpec.makeMeasureSpec(  
  1486.                             (int) (childHeightSize * lp.heightFactor),  
  1487.                             MeasureSpec.EXACTLY);  
  1488.                     child.measure(mChildWidthMeasureSpec, heightSpec);  
  1489.                 }  
  1490.             }  
  1491.         }  
  1492.     }  
  1493.   
  1494.     @Override  
  1495.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  1496.         super.onSizeChanged(w, h, oldw, oldh);  
  1497.   
  1498.         // Make sure scroll position is set correctly.  
  1499.         if (w != oldw) {  
  1500.             recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);  
  1501.         }  
  1502.     }  
  1503.   
  1504.     private void recomputeScrollPosition(int height, int oldHeight, int margin,  
  1505.             int oldMargin) {  
  1506.         if (oldHeight > 0 && !mItems.isEmpty()) {  
  1507.   
  1508.             final int heightWithMargin = height + margin;  
  1509.             final int oldHeightWithMargin = oldHeight + oldMargin;  
  1510.             final int ypos = getScrollY();  
  1511.             final float pageOffset = (float) ypos / oldHeightWithMargin;  
  1512.             final int newOffsetPixels = (int) (pageOffset * heightWithMargin);  
  1513.   
  1514.             scrollTo(getScrollX(), newOffsetPixels);  
  1515.             if (!mScroller.isFinished()) {  
  1516.                 // We now return to your regularly scheduled scroll, already in  
  1517.                 // progress.  
  1518.                 final int newDuration = mScroller.getDuration()  
  1519.                         - mScroller.timePassed();  
  1520.                 ItemInfo targetInfo = infoForPosition(mCurItem);  
  1521.                 mScroller.startScroll(0, newOffsetPixels, 0,  
  1522.                         (int) (targetInfo.offset * height), newDuration);  
  1523.             }  
  1524.         } else {  
  1525.             final ItemInfo ii = infoForPosition(mCurItem);  
  1526.             final float scrollOffset = ii != null ? Math.min(ii.offset,  
  1527.                     mLastOffset) : 0;  
  1528.             final int scrollPos = (int) (scrollOffset * height);  
  1529.             if (scrollPos != getScrollY()) {  
  1530.                 completeScroll(false);  
  1531.                 scrollTo(getScrollX(), scrollPos);  
  1532.             }  
  1533.         }  
  1534.     }  
  1535.   
  1536.     @Override  
  1537.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  1538.         if (DEBUG)  
  1539.             Log.d(TAG, "onLayout");  
  1540.   
  1541.         mInLayout = true;  
  1542.         populate();  
  1543.         mInLayout = false;  
  1544.   
  1545.         final int count = getChildCount();  
  1546.         int width = r - l;  
  1547.         int height = b - t;  
  1548.         int paddingLeft = getPaddingLeft();  
  1549.         int paddingTop = getPaddingTop();  
  1550.         int paddingRight = getPaddingRight();  
  1551.         int paddingBottom = getPaddingBottom();  
  1552.         final int scrollY = getScrollY();  
  1553.   
  1554.         int decorCount = 0;  
  1555.   
  1556.         // First pass - decor views. We need to do this in two passes so that  
  1557.         // we have the proper offsets for non-decor views later.  
  1558.         for (int i = 0; i < count; i++) {  
  1559.             final View child = getChildAt(i);  
  1560.             if (child.getVisibility() != GONE) {  
  1561.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1562.                 int childLeft = 0;  
  1563.                 int childTop = 0;  
  1564.                 if (lp.isDecor) {  
  1565.                     final int hgrav = lp.gravity  
  1566.                             & Gravity.HORIZONTAL_GRAVITY_MASK;  
  1567.                     final int vgrav = lp.gravity  
  1568.                             & Gravity.VERTICAL_GRAVITY_MASK;  
  1569.                     switch (hgrav) {  
  1570.                     default:  
  1571.                         childLeft = paddingLeft;  
  1572.                         break;  
  1573.                     case Gravity.LEFT:  
  1574.                         childLeft = paddingLeft;  
  1575.                         paddingLeft += child.getMeasuredWidth();  
  1576.                         break;  
  1577.                     case Gravity.CENTER_HORIZONTAL:  
  1578.                         childLeft = Math.max(  
  1579.                                 (width - child.getMeasuredWidth()) / 2,  
  1580.                                 paddingLeft);  
  1581.                         break;  
  1582.                     case Gravity.RIGHT:  
  1583.                         childLeft = width - paddingRight  
  1584.                                 - child.getMeasuredWidth();  
  1585.                         paddingRight += child.getMeasuredWidth();  
  1586.                         break;  
  1587.                     }  
  1588.                     switch (vgrav) {  
  1589.                     default:  
  1590.                         childTop = paddingTop;  
  1591.                         break;  
  1592.                     case Gravity.TOP:  
  1593.                         childTop = paddingTop;  
  1594.                         paddingTop += child.getMeasuredHeight();  
  1595.                         break;  
  1596.                     case Gravity.CENTER_VERTICAL:  
  1597.                         childTop = Math.max(  
  1598.                                 (height - child.getMeasuredHeight()) / 2,  
  1599.                                 paddingTop);  
  1600.                         break;  
  1601.                     case Gravity.BOTTOM:  
  1602.                         childTop = height - paddingBottom  
  1603.                                 - child.getMeasuredHeight();  
  1604.                         paddingBottom += child.getMeasuredHeight();  
  1605.                         break;  
  1606.                     }  
  1607.                     childTop += scrollY;  
  1608.                     child.layout(childLeft, childTop,  
  1609.                             childLeft + child.getMeasuredWidth(), childTop  
  1610.                                     + child.getMeasuredHeight());  
  1611.                     decorCount++;  
  1612.                 }  
  1613.             }  
  1614.         }  
  1615.   
  1616.         // Page views. Do this once we have the right padding offsets from  
  1617.         // above.  
  1618.         for (int i = 0; i < count; i++) {  
  1619.             final View child = getChildAt(i);  
  1620.             if (child.getVisibility() != GONE) {  
  1621.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1622.                 ItemInfo ii;  
  1623.                 if (!lp.isDecor && (ii = infoForChild(child)) != null) {  
  1624.                     int loff = (int) (height * ii.offset);  
  1625.   
  1626.                     int childLeft = paddingLeft;  
  1627.   
  1628.                     int childTop = paddingTop = loff;  
  1629.   
  1630.                     if (lp.needsMeasure) {  
  1631.                         // This was added during layout and needs measurement.  
  1632.                         // Do it now that we know what we're working with.  
  1633.                         lp.needsMeasure = false;  
  1634.                         final int widthSpec = MeasureSpec  
  1635.                                 .makeMeasureSpec(  
  1636.                                         (int) ((width - paddingLeft - paddingRight) * lp.widthFactor),  
  1637.                                         MeasureSpec.EXACTLY);  
  1638.                         final int heightSpec = MeasureSpec.makeMeasureSpec(  
  1639.                                 (int) (height - paddingTop - paddingBottom),  
  1640.                                 MeasureSpec.EXACTLY);  
  1641.                         child.measure(widthSpec, heightSpec);  
  1642.                     }  
  1643.                     if (DEBUG)  
  1644.                         Log.v(TAG,  
  1645.                                 "Positioning #" + i + " " + child + " f="  
  1646.                                         + ii.object + ":" + childLeft + ","  
  1647.                                         + childTop + " "  
  1648.                                         + child.getMeasuredWidth() + "x"  
  1649.                                         + child.getMeasuredHeight());  
  1650.                     child.layout(childLeft, childTop,  
  1651.                             childLeft + child.getMeasuredWidth(), childTop  
  1652.                                     + child.getMeasuredHeight());  
  1653.                 }  
  1654.             }  
  1655.         }  
  1656.         mLeftPageBounds = paddingLeft;  
  1657.         mRightPageBounds = width - paddingRight;  
  1658.         mDecorChildCount = decorCount;  
  1659.         mFirstLayout = false;  
  1660.     }  
  1661.   
  1662.     @Override  
  1663.     public void computeScroll() {  
  1664.         if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {  
  1665.             int oldX = getScrollX();  
  1666.             int oldY = getScrollY();  
  1667.             int x = mScroller.getCurrX();  
  1668.             int y = mScroller.getCurrY();  
  1669.   
  1670.             if (oldX != x || oldY != y) {  
  1671.                 scrollTo(x, y);  
  1672.                 if (!pageScrolled(x)) {  
  1673.                     mScroller.abortAnimation();  
  1674.                     scrollTo(0, y);  
  1675.                 }  
  1676.             }  
  1677.   
  1678.             // Keep on drawing until the animation has finished.  
  1679.             ViewCompat.postInvalidateOnAnimation(this);  
  1680.             return;  
  1681.         }  
  1682.   
  1683.         // Done with scroll, clean up state.  
  1684.         completeScroll(true);  
  1685.     }  
  1686.   
  1687.     private boolean pageScrolled(int ypos) {  
  1688.         if (mItems.size() == 0) {  
  1689.             mCalledSuper = false;  
  1690.             onPageScrolled(000);  
  1691.             if (!mCalledSuper) {  
  1692.                 throw new IllegalStateException(  
  1693.                         "onPageScrolled did not call superclass implementation");  
  1694.             }  
  1695.             return false;  
  1696.         }  
  1697.         final ItemInfo ii = infoForCurrentScrollPosition();  
  1698.         final int height = getHeight();  
  1699.   
  1700.         final int heightWithMargin = height + mPageMargin;  
  1701.   
  1702.         final float marginOffset = (float) mPageMargin / height;  
  1703.         final int currentPage = ii.position;  
  1704.         final float pageOffset = (((float) ypos / height) - ii.offset)  
  1705.                 / (ii.heightFactor + marginOffset);  
  1706.         final int offsetPixels = (int) (pageOffset * heightWithMargin);  
  1707.   
  1708.         mCalledSuper = false;  
  1709.         onPageScrolled(currentPage, pageOffset, offsetPixels);  
  1710.         if (!mCalledSuper) {  
  1711.             throw new IllegalStateException(  
  1712.                     "onPageScrolled did not call superclass implementation");  
  1713.         }  
  1714.         return true;  
  1715.     }  
  1716.   
  1717.     /** 
  1718.      * This method will be invoked when the current page is scrolled, either as 
  1719.      * part of a programmatically initiated smooth scroll or a user initiated 
  1720.      * touch scroll. If you override this method you must call through to the 
  1721.      * superclass implementation (e.g. super.onPageScrolled(position, offset, 
  1722.      * offsetPixels)) before onPageScrolled returns. 
  1723.      *  
  1724.      * @param position 
  1725.      *            Position index of the first page currently being displayed. 
  1726.      *            Page position+1 will be visible if positionOffset is nonzero. 
  1727.      * @param offset 
  1728.      *            Value from [0, 1) indicating the offset from the page at 
  1729.      *            position. 
  1730.      * @param offsetPixels 
  1731.      *            Value in pixels indicating the offset from position. 
  1732.      */  
  1733.     protected void onPageScrolled(int position, float offset, int offsetPixels) {  
  1734.         // Offset any decor views if needed - keep them on-screen at all times.  
  1735.         if (mDecorChildCount > 0) {  
  1736.             final int scrollY = getScrollY();  
  1737.   
  1738.             int paddingTop = getPaddingTop();  
  1739.             int paddingBottom = getPaddingBottom();  
  1740.   
  1741.             final int height = getHeight();  
  1742.   
  1743.             final int childCount = getChildCount();  
  1744.             for (int i = 0; i < childCount; i++) {  
  1745.                 final View child = getChildAt(i);  
  1746.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1747.                 if (!lp.isDecor)  
  1748.                     continue;  
  1749.   
  1750.                 final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;  
  1751.                 int childTop = 0;  
  1752.   
  1753.                 switch (vgrav) {  
  1754.                 default:  
  1755.                     childTop = paddingTop;  
  1756.                     break;  
  1757.                 case Gravity.TOP:  
  1758.                     childTop = paddingTop;  
  1759.                     paddingTop += child.getHeight();  
  1760.                     break;  
  1761.                 case Gravity.CENTER_VERTICAL:  
  1762.                     childTop = Math.max(  
  1763.                             (height - child.getMeasuredHeight()) / 2,  
  1764.                             paddingTop);  
  1765.                     break;  
  1766.                 case Gravity.BOTTOM:  
  1767.                     childTop = height - paddingBottom  
  1768.                             - child.getMeasuredHeight();  
  1769.                     paddingBottom += child.getMeasuredHeight();  
  1770.                     break;  
  1771.                 }  
  1772.                 childTop += scrollY;  
  1773.   
  1774.                 final int childOffset = childTop - child.getTop();  
  1775.                 if (childOffset != 0) {  
  1776.                     child.offsetTopAndBottom(childOffset);  
  1777.                 }  
  1778.             }  
  1779.         }  
  1780.   
  1781.         if (mSeenPositionMin < 0 || position < mSeenPositionMin) {  
  1782.             mSeenPositionMin = position;  
  1783.         }  
  1784.         if (mSeenPositionMax < 0  
  1785.                 || FloatMath.ceil(position + offset) > mSeenPositionMax) {  
  1786.             mSeenPositionMax = position + 1;  
  1787.         }  
  1788.   
  1789.         if (mOnPageChangeListener != null) {  
  1790.             mOnPageChangeListener  
  1791.                     .onPageScrolled(position, offset, offsetPixels);  
  1792.         }  
  1793.         if (mInternalPageChangeListener != null) {  
  1794.             mInternalPageChangeListener.onPageScrolled(position, offset,  
  1795.                     offsetPixels);  
  1796.         }  
  1797.   
  1798.         if (mPageTransformer != null) {  
  1799.             final int scrollY = getScrollY();  
  1800.             final int childCount = getChildCount();  
  1801.             for (int i = 0; i < childCount; i++) {  
  1802.                 final View child = getChildAt(i);  
  1803.                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();  
  1804.   
  1805.                 if (lp.isDecor)  
  1806.                     continue;  
  1807.   
  1808.                 final float transformPos = (float) (child.getTop() - scrollY)  
  1809.                         / getHeight();  
  1810.                 mPageTransformer.transformPage(child, transformPos);  
  1811.             }  
  1812.         }  
  1813.   
  1814.         mCalledSuper = true;  
  1815.     }  
  1816.   
  1817.     private void completeScroll(boolean postEvents) {  
  1818.         boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;  
  1819.         if (needPopulate) {  
  1820.             // Done with scroll, no longer want to cache view drawing.  
  1821.             setScrollingCacheEnabled(false);  
  1822.             mScroller.abortAnimation();  
  1823.             int oldX = getScrollX();  
  1824.             int oldY = getScrollY();  
  1825.             int x = mScroller.getCurrX();  
  1826.             int y = mScroller.getCurrY();  
  1827.             if (oldX != x || oldY != y) {  
  1828.                 scrollTo(x, y);  
  1829.             }  
  1830.         }  
  1831.         mPopulatePending = false;  
  1832.         for (int i = 0; i < mItems.size(); i++) {  
  1833.             ItemInfo ii = mItems.get(i);  
  1834.             if (ii.scrolling) {  
  1835.                 needPopulate = true;  
  1836.                 ii.scrolling = false;  
  1837.             }  
  1838.         }  
  1839.         if (needPopulate) {  
  1840.             if (postEvents) {  
  1841.                 ViewCompat.postOnAnimation(this, mEndScrollRunnable);  
  1842.             } else {  
  1843.                 mEndScrollRunnable.run();  
  1844.             }  
  1845.         }  
  1846.     }  
  1847.   
  1848.     private boolean isGutterDrag(float y, float dy) {  
  1849.         return (y < mGutterSize && dy > 0)  
  1850.                 || (y > getHeight() - mGutterSize && dy < 0);  
  1851.     }  
  1852.   
  1853.     private void enableLayers(boolean enable) {  
  1854.         final int childCount = getChildCount();  
  1855.         for (int i = 0; i < childCount; i++) {  
  1856.             final int layerType = enable ? ViewCompat.LAYER_TYPE_HARDWARE  
  1857.                     : ViewCompat.LAYER_TYPE_NONE;  
  1858.             ViewCompat.setLayerType(getChildAt(i), layerType, null);  
  1859.         }  
  1860.     }  
  1861.   
  1862.     @Override  
  1863.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  1864.         /* 
  1865.          * This method JUST determines whether we want to intercept the motion. 
  1866.          * If we return true, onMotionEvent will be called and we do the actual 
  1867.          * scrolling there. 
  1868.          */  
  1869.   
  1870.         final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;  
  1871.   
  1872.         // Always take care of the touch gesture being complete.  
  1873.         if (action == MotionEvent.ACTION_CANCEL  
  1874.                 || action == MotionEvent.ACTION_UP) {  
  1875.             // Release the drag.  
  1876.             if (DEBUG)  
  1877.                 Log.v(TAG, "Intercept done!");  
  1878.             mIsBeingDragged = false;  
  1879.             mIsUnableToDrag = false;  
  1880.             mActivePointerId = INVALID_POINTER;  
  1881.             if (mVelocityTracker != null) {  
  1882.                 mVelocityTracker.recycle();  
  1883.                 mVelocityTracker = null;  
  1884.             }  
  1885.             return false;  
  1886.         }  
  1887.   
  1888.         // Nothing more to do here if we have decided whether or not we  
  1889.         // are dragging.  
  1890.         if (action != MotionEvent.ACTION_DOWN) {  
  1891.             if (mIsBeingDragged) {  
  1892.                 if (DEBUG)  
  1893.                     Log.v(TAG, "Intercept returning true!");  
  1894.                 return true;  
  1895.             }  
  1896.             if (mIsUnableToDrag) {  
  1897.                 if (DEBUG)  
  1898.                     Log.v(TAG, "Intercept returning false!");  
  1899.                 return false;  
  1900.             }  
  1901.         }  
  1902.   
  1903.         switch (action) {  
  1904.         case MotionEvent.ACTION_MOVE: {  
  1905.             /* 
  1906.              * mIsBeingDragged == false, otherwise the shortcut would have 
  1907.              * caught it. Check whether the user has moved far enough from his 
  1908.              * original down touch. 
  1909.              */  
  1910.   
  1911.             /* 
  1912.              * Locally do absolute value. mLastMotionY is set to the y value of 
  1913.              * the down event. 
  1914.              */  
  1915.             final int activePointerId = mActivePointerId;  
  1916.             if (activePointerId == INVALID_POINTER) {  
  1917.                 // If we don't have a valid id, the touch down wasn't on  
  1918.                 // content.  
  1919.                 break;  
  1920.             }  
  1921.   
  1922.             final int pointerIndex = MotionEventCompat.findPointerIndex(ev,  
  1923.                     activePointerId);  
  1924.             final float x = MotionEventCompat.getX(ev, pointerIndex);  
  1925.             final float dx = x - mLastMotionX;  
  1926.             final float xDiff = Math.abs(dx);  
  1927.             final float y = MotionEventCompat.getY(ev, pointerIndex);  
  1928.             final float dy = y - mLastMotionY;  
  1929.             final float yDiff = Math.abs(y - mLastMotionY);  
  1930.             if (DEBUG)  
  1931.                 Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + ","  
  1932.                         + yDiff);  
  1933.   
  1934.             if (dy != 0 && !isGutterDrag(mLastMotionY, dy)  
  1935.                     && canScroll(thisfalse, (int) dy, (int) x, (int) y)) {  
  1936.                 // Nested view has scrollable area under this point. Let it be  
  1937.                 // handled there.  
  1938.                 mInitialMotionY = mLastMotionY = y;  
  1939.                 mLastMotionX = x;  
  1940.                 mIsUnableToDrag = true;  
  1941.                 return false;  
  1942.             }  
  1943.             if (yDiff > mTouchSlop && yDiff > xDiff) {  
  1944.                 if (DEBUG)  
  1945.                     Log.v(TAG, "Starting drag!");  
  1946.                 mIsBeingDragged = true;  
  1947.                 setScrollState(SCROLL_STATE_DRAGGING);  
  1948.                 mLastMotionY = dy > 0 ? mInitialMotionY + mTouchSlop  
  1949.                         : mInitialMotionY - mTouchSlop;  
  1950.                 setScrollingCacheEnabled(true);  
  1951.             } else {  
  1952.                 if (xDiff > mTouchSlop) {  
  1953.                     // The finger has moved enough in the vertical  
  1954.                     // direction to be counted as a drag... abort  
  1955.                     // any attempt to drag horizontally, to work correctly  
  1956.                     // with children that have scrolling containers.  
  1957.                     if (DEBUG)  
  1958.                         Log.v(TAG, "Starting unable to drag!");  
  1959.                     mIsUnableToDrag = true;  
  1960.                 }  
  1961.             }  
  1962.             if (mIsBeingDragged) {  
  1963.                 // Scroll to follow the motion event  
  1964.                 if (performDrag(y)) {  
  1965.                     ViewCompat.postInvalidateOnAnimation(this);  
  1966.                 }  
  1967.             }  
  1968.             break;  
  1969.         }  
  1970.   
  1971.         case MotionEvent.ACTION_DOWN: {  
  1972.             /* 
  1973.              * Remember location of down touch. ACTION_DOWN always refers to 
  1974.              * pointer index 0. 
  1975.              */  
  1976.             mLastMotionY = mInitialMotionY = ev.getY();  
  1977.             mLastMotionX = ev.getX();  
  1978.             mActivePointerId = MotionEventCompat.getPointerId(ev, 0);  
  1979.             mIsUnableToDrag = false;  
  1980.   
  1981.             mScroller.computeScrollOffset();  
  1982.             if (mScrollState == SCROLL_STATE_SETTLING  
  1983.                     && Math.abs(mScroller.getFinalY() - mScroller.getCurrY()) > mCloseEnough) {  
  1984.                 // Let the user 'catch' the pager as it animates.  
  1985.                 mScroller.abortAnimation();  
  1986.                 mPopulatePending = false;  
  1987.                 populate();  
  1988.                 mIsBeingDragged = true;  
  1989.                 setScrollState(SCROLL_STATE_DRAGGING);  
  1990.             } else {  
  1991.                 completeScroll(false);  
  1992.                 mIsBeingDragged = false;  
  1993.             }  
  1994.   
  1995.             if (DEBUG)  
  1996.                 Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY  
  1997.                         + " mIsBeingDragged=" + mIsBeingDragged  
  1998.                         + "mIsUnableToDrag=" + mIsUnableToDrag);  
  1999.             break;  
  2000.         }  
  2001.   
  2002.         case MotionEventCompat.ACTION_POINTER_UP:  
  2003.             onSecondaryPointerUp(ev);  
  2004.             break;  
  2005.         }  
  2006.   
  2007.         if (mVelocityTracker == null) {  
  2008.             mVelocityTracker = VelocityTracker.obtain();  
  2009.         }  
  2010.         mVelocityTracker.addMovement(ev);  
  2011.   
  2012.         /* 
  2013.          * The only time we want to intercept motion events is if we are in the 
  2014.          * drag mode. 
  2015.          */  
  2016.         return mIsBeingDragged;  
  2017.     }  
  2018.   
  2019.     @Override  
  2020.     public boolean onTouchEvent(MotionEvent ev) {  
  2021.         if (mFakeDragging) {  
  2022.             // A fake drag is in progress already, ignore this real one  
  2023.             // but still eat the touch events.  
  2024.             // (It is likely that the user is multi-touching the screen.)  
  2025.             return true;  
  2026.         }  
  2027.   
  2028.         if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {  
  2029.             // Don't handle edge touches immediately -- they may actually belong  
  2030.             // to one of our  
  2031.             // descendants.  
  2032.             return false;  
  2033.         }  
  2034.   
  2035.         if (mAdapter == null || mAdapter.getCount() == 0) {  
  2036.             // Nothing to present or scroll; nothing to touch.  
  2037.             return false;  
  2038.         }  
  2039.   
  2040.         if (mVelocityTracker == null) {  
  2041.             mVelocityTracker = VelocityTracker.obtain();  
  2042.         }  
  2043.         mVelocityTracker.addMovement(ev);  
  2044.   
  2045.         final int action = ev.getAction();  
  2046.         boolean needsInvalidate = false;  
  2047.   
  2048.         switch (action & MotionEventCompat.ACTION_MASK) {  
  2049.         case MotionEvent.ACTION_DOWN: {  
  2050.             mScroller.abortAnimation();  
  2051.             mPopulatePending = false;  
  2052.             populate();  
  2053.             mIsBeingDragged = true;  
  2054.             setScrollState(SCROLL_STATE_DRAGGING);  
  2055.   
  2056.             // Remember where the motion event started  
  2057.             mLastMotionY = mInitialMotionY = ev.getY();  
  2058.             mActivePointerId = MotionEventCompat.getPointerId(ev, 0);  
  2059.             break;  
  2060.         }  
  2061.         case MotionEvent.ACTION_MOVE:  
  2062.             if (!mIsBeingDragged) {  
  2063.                 final int pointerIndex = MotionEventCompat.findPointerIndex(ev,  
  2064.                         mActivePointerId);  
  2065.                 final float x = MotionEventCompat.getX(ev, pointerIndex);  
  2066.                 final float xDiff = Math.abs(x - mLastMotionX);  
  2067.                 final float y = MotionEventCompat.getY(ev, pointerIndex);  
  2068.                 final float yDiff = Math.abs(y - mLastMotionY);  
  2069.   
  2070.                 if (DEBUG)  
  2071.                     Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff  
  2072.                             + "," + yDiff);  
  2073.   
  2074.                 if (yDiff > mTouchSlop && yDiff > xDiff) {  
  2075.                     if (DEBUG)  
  2076.                         Log.v(TAG, "Starting drag!");  
  2077.                     mIsBeingDragged = true;  
  2078.                     mLastMotionY = y - mInitialMotionY > 0 ? mInitialMotionY  
  2079.                             + mTouchSlop : mInitialMotionY - mTouchSlop;  
  2080.                     setScrollState(SCROLL_STATE_DRAGGING);  
  2081.                     setScrollingCacheEnabled(true);  
  2082.                 }  
  2083.             }  
  2084.             // Not else! Note that mIsBeingDragged can be set above.  
  2085.             if (mIsBeingDragged) {  
  2086.                 // Scroll to follow the motion event  
  2087.                 final int activePointerIndex = MotionEventCompat  
  2088.                         .findPointerIndex(ev, mActivePointerId);  
  2089.                 final float y = MotionEventCompat.getY(ev, activePointerIndex);  
  2090.                 needsInvalidate |= performDrag(y);  
  2091.             }  
  2092.             break;  
  2093.         case MotionEvent.ACTION_UP:  
  2094.             if (mIsBeingDragged) {  
  2095.                 final VelocityTracker velocityTracker = mVelocityTracker;  
  2096.                 velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
  2097.                 int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(  
  2098.                         velocityTracker, mActivePointerId);  
  2099.                 mPopulatePending = true;  
  2100.                 final int height = getHeight();  
  2101.                 final int scrollY = getScrollY();  
  2102.                 final ItemInfo ii = infoForCurrentScrollPosition();  
  2103.                 final int currentPage = ii.position;  
  2104.                 final float pageOffset = (((float) scrollY / height) - ii.offset)  
  2105.                         / ii.heightFactor;  
  2106.                 final int activePointerIndex = MotionEventCompat  
  2107.                         .findPointerIndex(ev, mActivePointerId);  
  2108.                 final float y = MotionEventCompat.getY(ev, activePointerIndex);  
  2109.                 final int totalDelta = (int) (y - mInitialMotionX);  
  2110.                 int nextPage = determineTargetPage(currentPage, pageOffset,  
  2111.                         initialVelocity, totalDelta);  
  2112.                 setCurrentItemInternal(nextPage, truetrue, initialVelocity);  
  2113.   
  2114.                 mActivePointerId = INVALID_POINTER;  
  2115.                 endDrag();  
  2116.                 needsInvalidate = mTopEdge.onRelease()  
  2117.                         | mBottomEdge.onRelease();  
  2118.             }  
  2119.             break;  
  2120.         case MotionEvent.ACTION_CANCEL:  
  2121.             if (mIsBeingDragged) {  
  2122.                 scrollToItem(mCurItem, true0false);  
  2123.                 mActivePointerId = INVALID_POINTER;  
  2124.                 endDrag();  
  2125.                 needsInvalidate = mTopEdge.onRelease()  
  2126.                         | mBottomEdge.onRelease();  
  2127.             }  
  2128.             break;  
  2129.         case MotionEventCompat.ACTION_POINTER_DOWN: {  
  2130.             final int index = MotionEventCompat.getActionIndex(ev);  
  2131.             final float y = MotionEventCompat.getY(ev, index);  
  2132.             mLastMotionY = y;  
  2133.             mActivePointerId = MotionEventCompat.getPointerId(ev, index);  
  2134.             break;  
  2135.         }  
  2136.         case MotionEventCompat.ACTION_POINTER_UP:  
  2137.             onSecondaryPointerUp(ev);  
  2138.             mLastMotionY = MotionEventCompat.getY(ev,  
  2139.                     MotionEventCompat.findPointerIndex(ev, mActivePointerId));  
  2140.             break;  
  2141.         }  
  2142.         if (needsInvalidate) {  
  2143.             ViewCompat.postInvalidateOnAnimation(this);  
  2144.         }  
  2145.         return true;  
  2146.     }  
  2147.   
  2148.     private boolean performDrag(float y) {  
  2149.         boolean needsInvalidate = false;  
  2150.   
  2151.         final float deltaY = mLastMotionY - y;  
  2152.         mLastMotionY = y;  
  2153.   
  2154.         float oldScrollY = getScrollY();  
  2155.         float scrollY = oldScrollY + deltaY;  
  2156.         final int height = getHeight();  
  2157.   
  2158.         float topBound = height * mFirstOffset;  
  2159.         float bottomBound = height * mLastOffset;  
  2160.         boolean topAbsolute = true;  
  2161.         boolean bottomAbsolute = true;  
  2162.   
  2163.         final ItemInfo firstItem = mItems.get(0);  
  2164.         final ItemInfo lastItem = mItems.get(mItems.size() - 1);  
  2165.         if (firstItem.position != 0) {  
  2166.             topAbsolute = false;  
  2167.             topBound = firstItem.offset * height;  
  2168.         }  
  2169.         if (lastItem.position != mAdapter.getCount() - 1) {  
  2170.             bottomAbsolute = false;  
  2171.             bottomBound = lastItem.offset * height;  
  2172.         }  
  2173.   
  2174.         if (scrollY < topBound) {  
  2175.             if (topAbsolute) {  
  2176.                 float over = topBound - scrollY;  
  2177.                 needsInvalidate = mTopEdge.onPull(Math.abs(over) / height);  
  2178.             }  
  2179.             scrollY = topBound;  
  2180.         } else if (scrollY > bottomBound) {  
  2181.             if (bottomAbsolute) {  
  2182.                 float over = scrollY - bottomBound;  
  2183.                 needsInvalidate = mBottomEdge.onPull(Math.abs(over) / height);  
  2184.             }  
  2185.             scrollY = bottomBound;  
  2186.         }  
  2187.   
  2188.         // Don't lose the rounded component  
  2189.         mLastMotionY += scrollY - (int) scrollY;  
  2190.         scrollTo(getScrollX(), (int) scrollY);  
  2191.         pageScrolled((int) scrollY);  
  2192.   
  2193.         return needsInvalidate;  
  2194.     }  
  2195.   
  2196.     /** 
  2197.      * @return Info about the page at the current scroll position. This can be 
  2198.      *         synthetic for a missing middle page; the 'object' field can be 
  2199.      *         null. 
  2200.      */  
  2201.     private ItemInfo infoForCurrentScrollPosition() {  
  2202.         final int height = getHeight();  
  2203.         final float scrollOffset = height > 0 ? (float) getScrollY() / height  
  2204.                 : 0;  
  2205.         final float marginOffset = height > 0 ? (float) mPageMargin / height  
  2206.                 : 0;  
  2207.   
  2208.         int lastPos = -1;  
  2209.         float lastOffset = 0.f;  
  2210.         float lastHeight = 0.f;  
  2211.         boolean first = true;  
  2212.   
  2213.         ItemInfo lastItem = null;  
  2214.         for (int i = 0; i < mItems.size(); i++) {  
  2215.             ItemInfo ii = mItems.get(i);  
  2216.             float offset;  
  2217.             if (!first && ii.position != lastPos + 1) {  
  2218.                 // Create a synthetic item for a missing page.  
  2219.                 ii = mTempItem;  
  2220.                 ii.offset = lastOffset + lastHeight + marginOffset;  
  2221.                 ii.position = lastPos + 1;  
  2222.                 ii.widthFactor = mAdapter.getPageWidth(ii.position);  
  2223.                 i--;  
  2224.             }  
  2225.             offset = ii.offset;  
  2226.   
  2227.             final float topBound = offset;  
  2228.             final float bottomBound = offset + ii.heightFactor + marginOffset;  
  2229.             if (first || scrollOffset >= topBound) {  
  2230.                 if (scrollOffset < bottomBound || i == mItems.size() - 1) {  
  2231.                     return ii;  
  2232.                 }  
  2233.             } else {  
  2234.                 return lastItem;  
  2235.             }  
  2236.             first = false;  
  2237.             lastPos = ii.position;  
  2238.             lastOffset = offset;  
  2239.             lastHeight = ii.heightFactor;  
  2240.             lastItem = ii;  
  2241.         }  
  2242.   
  2243.         return lastItem;  
  2244.     }  
  2245.   
  2246.     private int determineTargetPage(int currentPage, float pageOffset,  
  2247.             int velocity, int deltaY) {  
  2248.         int targetPage;  
  2249.         if (Math.abs(deltaY) > mFlingDistance  
  2250.                 && Math.abs(velocity) > mMinimumVelocity) {  
  2251.             targetPage = velocity > 0 ? currentPage : currentPage + 1;  
  2252.         } else if (mSeenPositionMin >= 0 && mSeenPositionMin < currentPage  
  2253.                 && pageOffset < 0.5f) {  
  2254.             targetPage = currentPage + 1;  
  2255.         } else if (mSeenPositionMax >= 0 && mSeenPositionMax > currentPage + 1  
  2256.                 && pageOffset >= 0.5f) {  
  2257.             targetPage = currentPage - 1;  
  2258.         } else {  
  2259.             targetPage = (int) (currentPage + pageOffset + 0.5f);  
  2260.         }  
  2261.   
  2262.         if (mItems.size() > 0) {  
  2263.             final ItemInfo firstItem = mItems.get(0);  
  2264.             final ItemInfo lastItem = mItems.get(mItems.size() - 1);  
  2265.   
  2266.             // Only let the user target pages we have items for  
  2267.             targetPage = Math.max(firstItem.position,  
  2268.                     Math.min(targetPage, lastItem.position));  
  2269.         }  
  2270.   
  2271.         return targetPage;  
  2272.     }  
  2273.   
  2274.     @Override  
  2275.     public void draw(Canvas canvas) {  
  2276.         super.draw(canvas);  
  2277.         boolean needsInvalidate = false;  
  2278.   
  2279.         final int overScrollMode = ViewCompat.getOverScrollMode(this);  
  2280.         if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS  
  2281.                 || (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS  
  2282.                         && mAdapter != null && mAdapter.getCount() > 1)) {  
  2283.             if (!mTopEdge.isFinished()) {  
  2284.                 final int height = getHeight();  
  2285.                 final int width = getWidth() - getPaddingLeft()  
  2286.                         - getPaddingRight();  
  2287.   
  2288.                 mTopEdge.setSize(width, height);  
  2289.   
  2290.                 needsInvalidate |= mTopEdge.draw(canvas);  
  2291.             }  
  2292.             if (!mBottomEdge.isFinished()) {  
  2293.                 // TODO: fix me!  
  2294.                 final int height = getHeight();  
  2295.                 final int width = getWidth() - getPaddingLeft()  
  2296.                         - getPaddingRight();  
  2297.   
  2298.                 // canvas.rotate(90);  
  2299.                 // canvas.rotate(180);  
  2300.                 // canvas.translate(-getPaddingTop(), -(mLastOffset + 1) *  
  2301.                 // width);  
  2302.                 // canvas.translate(-(mLastOffset + 1) * height,  
  2303.                 // -getPaddingRight());  
  2304.   
  2305.                 mBottomEdge.setSize(width, height);  
  2306.                 // mBottomEdge.setSize(height, width);  
  2307.   
  2308.                 needsInvalidate |= mBottomEdge.draw(canvas);  
  2309.                 // canvas.restoreToCount(restoreCount);  
  2310.             }  
  2311.         } else {  
  2312.             mTopEdge.finish();  
  2313.             mBottomEdge.finish();  
  2314.         }  
  2315.   
  2316.         if (needsInvalidate) {  
  2317.             // Keep animating  
  2318.             ViewCompat.postInvalidateOnAnimation(this);  
  2319.         }  
  2320.     }  
  2321.   
  2322.     @Override  
  2323.     protected void onDraw(Canvas canvas) {  
  2324.         super.onDraw(canvas);  
  2325.   
  2326.         // Draw the margin drawable between pages if needed.  
  2327.         if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0  
  2328.                 && mAdapter != null) {  
  2329.             final int scrollY = getScrollY();  
  2330.             final int height = getHeight();  
  2331.   
  2332.             final float marginOffset = (float) mPageMargin / height;  
  2333.             int itemIndex = 0;  
  2334.             ItemInfo ii = mItems.get(0);  
  2335.             float offset = ii.offset;  
  2336.             final int itemCount = mItems.size();  
  2337.             final int firstPos = ii.position;  
  2338.             final int lastPos = mItems.get(itemCount - 1).position;  
  2339.             for (int pos = firstPos; pos < lastPos; pos++) {  
  2340.                 while (pos > ii.position && itemIndex < itemCount) {  
  2341.                     ii = mItems.get(++itemIndex);  
  2342.                 }  
  2343.   
  2344.                 float drawAt;  
  2345.                 if (pos == ii.position) {  
  2346.                     drawAt = (ii.offset + ii.heightFactor) * height;  
  2347.                     offset = ii.offset + ii.heightFactor + marginOffset;  
  2348.                 } else {  
  2349.                     float heightFactor = mAdapter.getPageWidth(pos);  
  2350.                     drawAt = (offset + heightFactor) * height;  
  2351.                     offset += heightFactor + marginOffset;  
  2352.                 }  
  2353.   
  2354.                 if (drawAt + mPageMargin > scrollY) {  
  2355.                     mMarginDrawable.setBounds(mLeftPageBounds, (int) drawAt,  
  2356.                             mRightPageBounds,  
  2357.                             (int) (drawAt + mPageMargin + 0.5f));  
  2358.                     mMarginDrawable.draw(canvas);  
  2359.                 }  
  2360.   
  2361.                 if (drawAt > scrollY + height) {  
  2362.                     break// No more visible, no sense in continuing  
  2363.                 }  
  2364.             }  
  2365.         }  
  2366.     }  
  2367.   
  2368.     /** 
  2369.      * Start a fake drag of the pager. 
  2370.      *  
  2371.      * <p> 
  2372.      * A fake drag can be useful if you want to synchronize the motion of the 
  2373.      * ViewPager with the touch scrolling of another view, while still letting 
  2374.      * the ViewPager control the snapping motion and fling behavior. (e.g. 
  2375.      * parallax-scrolling tabs.) Call {@link #fakeDragBy(float)} to simulate the 
  2376.      * actual drag motion. Call {@link #endFakeDrag()} to complete the fake drag 
  2377.      * and fling as necessary. 
  2378.      *  
  2379.      * <p> 
  2380.      * During a fake drag the ViewPager will ignore all touch events. If a real 
  2381.      * drag is already in progress, this method will return false. 
  2382.      *  
  2383.      * @return true if the fake drag began successfully, false if it could not 
  2384.      *         be started. 
  2385.      *  
  2386.      * @see #fakeDragBy(float) 
  2387.      * @see #endFakeDrag() 
  2388.      */  
  2389.     public boolean beginFakeDrag() {  
  2390.         if (mIsBeingDragged) {  
  2391.             return false;  
  2392.         }  
  2393.         mFakeDragging = true;  
  2394.         setScrollState(SCROLL_STATE_DRAGGING);  
  2395.         mInitialMotionY = mLastMotionY = 0;  
  2396.         if (mVelocityTracker == null) {  
  2397.             mVelocityTracker = VelocityTracker.obtain();  
  2398.         } else {  
  2399.             mVelocityTracker.clear();  
  2400.         }  
  2401.         final long time = SystemClock.uptimeMillis();  
  2402.         final MotionEvent ev = MotionEvent.obtain(time, time,  
  2403.                 MotionEvent.ACTION_DOWN, 000);  
  2404.         mVelocityTracker.addMovement(ev);  
  2405.         ev.recycle();  
  2406.         mFakeDragBeginTime = time;  
  2407.         return true;  
  2408.     }  
  2409.   
  2410.     /** 
  2411.      * End a fake drag of the pager. 
  2412.      *  
  2413.      * @see #beginFakeDrag() 
  2414.      * @see #fakeDragBy(float) 
  2415.      */  
  2416.     public void endFakeDrag() {  
  2417.         if (!mFakeDragging) {  
  2418.             throw new IllegalStateException(  
  2419.                     "No fake drag in progress. Call beginFakeDrag first.");  
  2420.         }  
  2421.   
  2422.         final VelocityTracker velocityTracker = mVelocityTracker;  
  2423.         velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
  2424.         int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(  
  2425.                 velocityTracker, mActivePointerId);  
  2426.         mPopulatePending = true;  
  2427.         final int height = getHeight();  
  2428.         final int scrollY = getScrollY();  
  2429.         final ItemInfo ii = infoForCurrentScrollPosition();  
  2430.         final int currentPage = ii.position;  
  2431.         final float pageOffset = (((float) scrollY / height) - ii.offset)  
  2432.                 / ii.heightFactor;  
  2433.         final int totalDelta = (int) (mLastMotionY - mInitialMotionY);  
  2434.         int nextPage = determineTargetPage(currentPage, pageOffset,  
  2435.                 initialVelocity, totalDelta);  
  2436.         setCurrentItemInternal(nextPage, truetrue, initialVelocity);  
  2437.         endDrag();  
  2438.   
  2439.         mFakeDragging = false;  
  2440.     }  
  2441.   
  2442.     /** 
  2443.      * Fake drag by an offset in pixels. You must have called 
  2444.      * {@link #beginFakeDrag()} first. 
  2445.      *  
  2446.      * @param xOffset 
  2447.      *            Offset in pixels to drag by. 
  2448.      * @see #beginFakeDrag() 
  2449.      * @see #endFakeDrag() 
  2450.      */  
  2451.     // public void fakeDragBy(float xOffset) {  
  2452.     public void fakeDragBy(float yOffset) {  
  2453.         if (!mFakeDragging) {  
  2454.             throw new IllegalStateException(  
  2455.                     "No fake drag in progress. Call beginFakeDrag first.");  
  2456.         }  
  2457.   
  2458.         mLastMotionY += yOffset;  
  2459.   
  2460.         float oldScrollY = getScrollY();  
  2461.         float scrollY = oldScrollY - yOffset;  
  2462.         final int height = getHeight();  
  2463.   
  2464.         float topBound = height * mFirstOffset;  
  2465.         float bottomBound = height * mLastOffset;  
  2466.   
  2467.         final ItemInfo firstItem = mItems.get(0);  
  2468.         final ItemInfo lastItem = mItems.get(mItems.size() - 1);  
  2469.         if (firstItem.position != 0) {  
  2470.             topBound = firstItem.offset * height;  
  2471.         }  
  2472.         if (lastItem.position != mAdapter.getCount() - 1) {  
  2473.             bottomBound = lastItem.offset * height;  
  2474.         }  
  2475.   
  2476.         if (scrollY < topBound) {  
  2477.             scrollY = topBound;  
  2478.         } else if (scrollY > bottomBound) {  
  2479.             scrollY = bottomBound;  
  2480.         }  
  2481.   
  2482.         // Don't lose the rounded component  
  2483.         mLastMotionY += scrollY - (int) scrollY;  
  2484.         scrollTo(getScrollX(), (int) scrollY);  
  2485.         pageScrolled((int) scrollY);  
  2486.   
  2487.         // Synthesize an event for the VelocityTracker.  
  2488.         final long time = SystemClock.uptimeMillis();  
  2489.         final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time,  
  2490.                 MotionEvent.ACTION_MOVE, 0, mLastMotionY, 0);  
  2491.         mVelocityTracker.addMovement(ev);  
  2492.         ev.recycle();  
  2493.     }  
  2494.   
  2495.     /** 
  2496.      * Returns true if a fake drag is in progress. 
  2497.      *  
  2498.      * @return true if currently in a fake drag, false otherwise. 
  2499.      *  
  2500.      * @see #beginFakeDrag() 
  2501.      * @see #fakeDragBy(float) 
  2502.      * @see #endFakeDrag() 
  2503.      */  
  2504.     public boolean isFakeDragging() {  
  2505.         return mFakeDragging;  
  2506.     }  
  2507.   
  2508.     private void onSecondaryPointerUp(MotionEvent ev) {  
  2509.         final int pointerIndex = MotionEventCompat.getActionIndex(ev);  
  2510.         final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);  
  2511.         if (pointerId == mActivePointerId) {  
  2512.             // This was our active pointer going up. Choose a new  
  2513.             // active pointer and adjust accordingly.  
  2514.             final int newPointerIndex = pointerIndex == 0 ? 1 : 0;  
  2515.             mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex);  
  2516.             mActivePointerId = MotionEventCompat.getPointerId(ev,  
  2517.                     newPointerIndex);  
  2518.             if (mVelocityTracker != null) {  
  2519.                 mVelocityTracker.clear();  
  2520.             }  
  2521.         }  
  2522.     }  
  2523.   
  2524.     private void endDrag() {  
  2525.         mIsBeingDragged = false;  
  2526.         mIsUnableToDrag = false;  
  2527.   
  2528.         if (mVelocityTracker != null) {  
  2529.             mVelocityTracker.recycle();  
  2530.             mVelocityTracker = null;  
  2531.         }  
  2532.     }  
  2533.   
  2534.     private void setScrollingCacheEnabled(boolean enabled) {  
  2535.         if (mScrollingCacheEnabled != enabled) {  
  2536.             mScrollingCacheEnabled = enabled;  
  2537.             if (USE_CACHE) {  
  2538.                 final int size = getChildCount();  
  2539.                 for (int i = 0; i < size; ++i) {  
  2540.                     final View child = getChildAt(i);  
  2541.                     if (child.getVisibility() != GONE) {  
  2542.                         child.setDrawingCacheEnabled(enabled);  
  2543.                     }  
  2544.                 }  
  2545.             }  
  2546.         }  
  2547.     }  
  2548.   
  2549.     /** 
  2550.      * Tests scrollability within child views of v given a delta of dx. 
  2551.      *  
  2552.      * @param v 
  2553.      *            View to test for horizontal scrollability 
  2554.      * @param checkV 
  2555.      *            Whether the view v passed should itself be checked for 
  2556.      *            scrollability (true), or just its children (false). 
  2557.      * @param dy 
  2558.      *            Delta scrolled in pixels 
  2559.      * @param x 
  2560.      *            X coordinate of the active touch point 
  2561.      * @param y 
  2562.      *            Y coordinate of the active touch point 
  2563.      * @return true if child views of v can be scrolled by delta of dy. 
  2564.      */  
  2565.     protected boolean canScroll(View v, boolean checkV, int dy, int x, int y) {  
  2566.         if (v instanceof ViewGroup) {  
  2567.             final ViewGroup group = (ViewGroup) v;  
  2568.             final int scrollX = v.getScrollX();  
  2569.             final int scrollY = v.getScrollY();  
  2570.             final int count = group.getChildCount();  
  2571.             // Count backwards - let topmost views consume scroll distance  
  2572.             // first.  
  2573.             for (int i = count - 1; i >= 0; i--) {  
  2574.                 // TODO: Add versioned support here for transformed views.  
  2575.                 // This will not work for transformed views in Honeycomb+  
  2576.                 final View child = group.getChildAt(i);  
  2577.                 if (x + scrollX >= child.getLeft()  
  2578.                         && x + scrollX < child.getRight()  
  2579.                         && y + scrollY >= child.getTop()  
  2580.                         && y + scrollY < child.getBottom()  
  2581.                         && canScroll(child, true, dy,  
  2582.                                 x + scrollX - child.getLeft(), y + scrollY  
  2583.                                         - child.getTop())) {  
  2584.                     return true;  
  2585.                 }  
  2586.             }  
  2587.         }  
  2588.         return checkV && ViewCompat.canScrollVertically(v, -dy);  
  2589.     }  
  2590.   
  2591.     @Override  
  2592.     public boolean dispatchKeyEvent(KeyEvent event) {  
  2593.         // Let the focused view and/or our descendants get the key first  
  2594.         return super.dispatchKeyEvent(event) || executeKeyEvent(event);  
  2595.     }  
  2596.   
  2597.     /** 
  2598.      * You can call this function yourself to have the scroll view perform 
  2599.      * scrolling from a key event, just as if the event had been dispatched to 
  2600.      * it by the view hierarchy. 
  2601.      *  
  2602.      * @param event 
  2603.      *            The key event to execute. 
  2604.      * @return Return true if the event was handled, else false. 
  2605.      */  
  2606.     public boolean executeKeyEvent(KeyEvent event) {  
  2607.         boolean handled = false;  
  2608.         if (event.getAction() == KeyEvent.ACTION_DOWN) {  
  2609.             switch (event.getKeyCode()) {  
  2610.             case KeyEvent.KEYCODE_DPAD_LEFT:  
  2611.                 handled = arrowScroll(FOCUS_LEFT);  
  2612.                 break;  
  2613.             case KeyEvent.KEYCODE_DPAD_RIGHT:  
  2614.                 handled = arrowScroll(FOCUS_RIGHT);  
  2615.                 break;  
  2616.             case KeyEvent.KEYCODE_TAB:  
  2617.                 if (Build.VERSION.SDK_INT >= 11) {  
  2618.                     // The focus finder had a bug handling FOCUS_FORWARD and  
  2619.                     // FOCUS_BACKWARD  
  2620.                     // before Android 3.0. Ignore the tab key on those devices.  
  2621.                     if (KeyEventCompat.hasNoModifiers(event)) {  
  2622.                         handled = arrowScroll(FOCUS_FORWARD);  
  2623.                     } else if (KeyEventCompat.hasModifiers(event,  
  2624.                             KeyEvent.META_SHIFT_ON)) {  
  2625.                         handled = arrowScroll(FOCUS_BACKWARD);  
  2626.                     }  
  2627.                 }  
  2628.                 break;  
  2629.             }  
  2630.         }  
  2631.         return handled;  
  2632.     }  
  2633.   
  2634.     public boolean arrowScroll(int direction) {  
  2635.         View currentFocused = findFocus();  
  2636.         if (currentFocused == this)  
  2637.             currentFocused = null;  
  2638.   
  2639.         boolean handled = false;  
  2640.   
  2641.         View nextFocused = FocusFinder.getInstance().findNextFocus(this,  
  2642.                 currentFocused, direction);  
  2643.         if (nextFocused != null && nextFocused != currentFocused) {  
  2644.             if (direction == View.FOCUS_UP) {  
  2645.                 // If there is nothing to the left, or this is causing us to  
  2646.                 // jump to the right, then what we really want to do is page  
  2647.                 // left.  
  2648.   
  2649.                 final int nextUp = getChildRectInPagerCoordinates(mTempRect,  
  2650.                         nextFocused).top;  
  2651.                 final int currUp = getChildRectInPagerCoordinates(mTempRect,  
  2652.                         currentFocused).top;  
  2653.   
  2654.                 if (currentFocused != null && nextUp >= currUp) {  
  2655.                     handled = pageUp();  
  2656.                 } else {  
  2657.                     handled = nextFocused.requestFocus();  
  2658.                 }  
  2659.             } else if (direction == View.FOCUS_RIGHT) {  
  2660.                 // If there is nothing to the right, or this is causing us to  
  2661.                 // jump to the left, then what we really want to do is page  
  2662.                 // right.  
  2663.   
  2664.                 final int nextDown = getChildRectInPagerCoordinates(mTempRect,  
  2665.                         nextFocused).bottom;  
  2666.                 final int currDown = getChildRectInPagerCoordinates(mTempRect,  
  2667.                         currentFocused).bottom;  
  2668.                 if (currentFocused != null && nextDown <= currDown) {  
  2669.                     handled = pageDown();  
  2670.                 } else {  
  2671.                     handled = nextFocused.requestFocus();  
  2672.                 }  
  2673.             }  
  2674.         } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {  
  2675.             // Trying to move left and nothing there; try to page.  
  2676.             handled = pageUp();  
  2677.         } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {  
  2678.             // Trying to move right and nothing there; try to page.  
  2679.             handled = pageDown();  
  2680.         }  
  2681.         if (handled) {  
  2682.             playSoundEffect(SoundEffectConstants  
  2683.                     .getContantForFocusDirection(direction));  
  2684.         }  
  2685.         return handled;  
  2686.     }  
  2687.   
  2688.     private Rect getChildRectInPagerCoordinates(Rect outRect, View child) {  
  2689.         if (outRect == null) {  
  2690.             outRect = new Rect();  
  2691.         }  
  2692.         if (child == null) {  
  2693.             outRect.set(0000);  
  2694.             return outRect;  
  2695.         }  
  2696.         outRect.left = child.getLeft();  
  2697.         outRect.right = child.getRight();  
  2698.         outRect.top = child.getTop();  
  2699.         outRect.bottom = child.getBottom();  
  2700.   
  2701.         ViewParent parent = child.getParent();  
  2702.         while (parent instanceof ViewGroup && parent != this) {  
  2703.             final ViewGroup group = (ViewGroup) parent;  
  2704.             outRect.left += group.getLeft();  
  2705.             outRect.right += group.getRight();  
  2706.             outRect.top += group.getTop();  
  2707.             outRect.bottom += group.getBottom();  
  2708.   
  2709.             parent = group.getParent();  
  2710.         }  
  2711.         return outRect;  
  2712.     }  
  2713.   
  2714.     boolean pageUp() {  
  2715.         if (mCurItem > 0) {  
  2716.             setCurrentItem(mCurItem - 1true);  
  2717.             return true;  
  2718.         }  
  2719.         return false;  
  2720.     }  
  2721.   
  2722.     boolean pageDown() {  
  2723.         if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) {  
  2724.             setCurrentItem(mCurItem + 1true);  
  2725.             return true;  
  2726.         }  
  2727.         return false;  
  2728.     }  
  2729.   
  2730.     /** 
  2731.      * We only want the current page that is being shown to be focusable. 
  2732.      */  
  2733.     @Override  
  2734.     public void addFocusables(ArrayList<View> views, int direction,  
  2735.             int focusableMode) {  
  2736.         final int focusableCount = views.size();  
  2737.   
  2738.         final int descendantFocusability = getDescendantFocusability();  
  2739.   
  2740.         if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {  
  2741.             for (int i = 0; i < getChildCount(); i++) {  
  2742.                 final View child = getChildAt(i);  
  2743.                 if (child.getVisibility() == VISIBLE) {  
  2744.                     ItemInfo ii = infoForChild(child);  
  2745.                     if (ii != null && ii.position == mCurItem) {  
  2746.                         child.addFocusables(views, direction, focusableMode);  
  2747.                     }  
  2748.                 }  
  2749.             }  
  2750.         }  
  2751.   
  2752.         // we add ourselves (if focusable) in all cases except for when we are  
  2753.         // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  
  2754.         // this is  
  2755.         // to avoid the focus search finding layouts when a more precise search  
  2756.         // among the focusable children would be more interesting.  
  2757.         if (descendantFocusability != FOCUS_AFTER_DESCENDANTS ||  
  2758.         // No focusable descendants  
  2759.                 (focusableCount == views.size())) {  
  2760.             // Note that we can't call the superclass here, because it will  
  2761.             // add all views in. So we need to do the same thing View does.  
  2762.             if (!isFocusable()) {  
  2763.                 return;  
  2764.             }  
  2765.             if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE  
  2766.                     && isInTouchMode() && !isFocusableInTouchMode()) {  
  2767.                 return;  
  2768.             }  
  2769.             if (views != null) {  
  2770.                 views.add(this);  
  2771.             }  
  2772.         }  
  2773.     }  
  2774.   
  2775.     /** 
  2776.      * We only want the current page that is being shown to be touchable. 
  2777.      */  
  2778.     @Override  
  2779.     public void addTouchables(ArrayList<View> views) {  
  2780.         // Note that we don't call super.addTouchables(), which means that  
  2781.         // we don't call View.addTouchables(). This is okay because a ViewPager  
  2782.         // is itself not touchable.  
  2783.         for (int i = 0; i < getChildCount(); i++) {  
  2784.             final View child = getChildAt(i);  
  2785.             if (child.getVisibility() == VISIBLE) {  
  2786.                 ItemInfo ii = infoForChild(child);  
  2787.                 if (ii != null && ii.position == mCurItem) {  
  2788.                     child.addTouchables(views);  
  2789.                 }  
  2790.             }  
  2791.         }  
  2792.     }  
  2793.   
  2794.     /** 
  2795.      * We only want the current page that is being shown to be focusable. 
  2796.      */  
  2797.     @Override  
  2798.     protected boolean onRequestFocusInDescendants(int direction,  
  2799.             Rect previouslyFocusedRect) {  
  2800.         int index;  
  2801.         int increment;  
  2802.         int end;  
  2803.         int count = getChildCount();  
  2804.         // TODO check  
  2805.         if ((direction & FOCUS_DOWN) != 0) {  
  2806.             index = 0;  
  2807.             increment = 1;  
  2808.             end = count;  
  2809.         } else {  
  2810.             index = count - 1;  
  2811.             increment = -1;  
  2812.             end = -1;  
  2813.         }  
  2814.         for (int i = index; i != end; i += increment) {  
  2815.             View child = getChildAt(i);  
  2816.             if (child.getVisibility() == VISIBLE) {  
  2817.                 ItemInfo ii = infoForChild(child);  
  2818.                 if (ii != null && ii.position == mCurItem) {  
  2819.                     if (child.requestFocus(direction, previouslyFocusedRect)) {  
  2820.                         return true;  
  2821.                     }  
  2822.                 }  
  2823.             }  
  2824.         }  
  2825.         return false;  
  2826.     }  
  2827.   
  2828.     @Override  
  2829.     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {  
  2830.         // ViewPagers should only report accessibility info for the current  
  2831.         // page,  
  2832.         // otherwise things get very confusing.  
  2833.   
  2834.         // TODO: Should this note something about the paging container?  
  2835.   
  2836.         final int childCount = getChildCount();  
  2837.         for (int i = 0; i < childCount; i++) {  
  2838.             final View child = getChildAt(i);  
  2839.             if (child.getVisibility() == VISIBLE) {  
  2840.                 final ItemInfo ii = infoForChild(child);  
  2841.                 if (ii != null && ii.position == mCurItem  
  2842.                         && child.dispatchPopulateAccessibilityEvent(event)) {  
  2843.                     return true;  
  2844.                 }  
  2845.             }  
  2846.         }  
  2847.   
  2848.         return false;  
  2849.     }  
  2850.   
  2851.     @Override  
  2852.     protected ViewGroup.LayoutParams generateDefaultLayoutParams() {  
  2853.         return new LayoutParams();  
  2854.     }  
  2855.   
  2856.     @Override  
  2857.     protected ViewGroup.LayoutParams generateLayoutParams(  
  2858.             ViewGroup.LayoutParams p) {  
  2859.         return generateDefaultLayoutParams();  
  2860.     }  
  2861.   
  2862.     @Override  
  2863.     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {  
  2864.         return p instanceof LayoutParams && super.checkLayoutParams(p);  
  2865.     }  
  2866.   
  2867.     @Override  
  2868.     public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {  
  2869.         return new LayoutParams(getContext(), attrs);  
  2870.     }  
  2871.   
  2872.     class MyAccessibilityDelegate extends AccessibilityDelegateCompat {  
  2873.   
  2874.         @Override  
  2875.         public void onInitializeAccessibilityEvent(View host,  
  2876.                 AccessibilityEvent event) {  
  2877.             super.onInitializeAccessibilityEvent(host, event);  
  2878.             event.setClassName(VerticalViewPager.class.getName());  
  2879.         }  
  2880.   
  2881.         @Override  
  2882.         public void onInitializeAccessibilityNodeInfo(View host,  
  2883.                 AccessibilityNodeInfoCompat info) {  
  2884.             super.onInitializeAccessibilityNodeInfo(host, info);  
  2885.             info.setClassName(VerticalViewPager.class.getName());  
  2886.             info.setScrollable(mAdapter != null && mAdapter.getCount() > 1);  
  2887.             if (mAdapter != null && mCurItem >= 0  
  2888.                     && mCurItem < mAdapter.getCount() - 1) {  
  2889.                 info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);  
  2890.             }  
  2891.             if (mAdapter != null && mCurItem > 0  
  2892.                     && mCurItem < mAdapter.getCount()) {  
  2893.                 info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);  
  2894.             }  
  2895.         }  
  2896.   
  2897.         @Override  
  2898.         public boolean performAccessibilityAction(View host, int action,  
  2899.                 Bundle args) {  
  2900.             if (super.performAccessibilityAction(host, action, args)) {  
  2901.                 return true;  
  2902.             }  
  2903.             switch (action) {  
  2904.             case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: {  
  2905.                 if (mAdapter != null && mCurItem >= 0  
  2906.                         && mCurItem < mAdapter.getCount() - 1) {  
  2907.                     setCurrentItem(mCurItem + 1);  
  2908.                     return true;  
  2909.                 }  
  2910.             }  
  2911.                 return false;  
  2912.             case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: {  
  2913.                 if (mAdapter != null && mCurItem > 0  
  2914.                         && mCurItem < mAdapter.getCount()) {  
  2915.                     setCurrentItem(mCurItem - 1);  
  2916.                     return true;  
  2917.                 }  
  2918.             }  
  2919.                 return false;  
  2920.             }  
  2921.             return false;  
  2922.         }  
  2923.     }  
  2924.   
  2925.     private class PagerObserver extends DataSetObserver {  
  2926.         @Override  
  2927.         public void onChanged() {  
  2928.             dataSetChanged();  
  2929.         }  
  2930.   
  2931.         @Override  
  2932.         public void onInvalidated() {  
  2933.             dataSetChanged();  
  2934.         }  
  2935.     }  
  2936.   
  2937.     /** 
  2938.      * Layout parameters that should be supplied for views added to a ViewPager. 
  2939.      */  
  2940.     public static class LayoutParams extends ViewGroup.LayoutParams {  
  2941.         /** 
  2942.          * true if this view is a decoration on the pager itself and not a view 
  2943.          * supplied by the adapter. 
  2944.          */  
  2945.         public boolean isDecor;  
  2946.   
  2947.         /** 
  2948.          * Gravity setting for use on decor views only: Where to position the 
  2949.          * view page within the overall ViewPager container; constants are 
  2950.          * defined in {@link android.view.Gravity}. 
  2951.          */  
  2952.         public int gravity;  
  2953.   
  2954.         /** 
  2955.          * Width as a 0-1 multiplier of the measured pager width 
  2956.          */  
  2957.         float widthFactor = 0.f;  
  2958.         float heightFactor = 0f;  
  2959.   
  2960.         /** 
  2961.          * true if this view was added during layout and needs to be measured 
  2962.          * before being positioned. 
  2963.          */  
  2964.         boolean needsMeasure;  
  2965.   
  2966.         /** 
  2967.          * Adapter position this view is for if !isDecor 
  2968.          */  
  2969.         int position;  
  2970.   
  2971.         /** 
  2972.          * Current child index within the ViewPager that this view occupies 
  2973.          */  
  2974.         int childIndex;  
  2975.   
  2976.         @SuppressWarnings("deprecation")  
  2977.         public LayoutParams() {  
  2978.             super(FILL_PARENT, FILL_PARENT);  
  2979.         }  
  2980.   
  2981.         public LayoutParams(Context context, AttributeSet attrs) {  
  2982.             super(context, attrs);  
  2983.   
  2984.             final TypedArray a = context.obtainStyledAttributes(attrs,  
  2985.                     LAYOUT_ATTRS);  
  2986.             gravity = a.getInteger(0, Gravity.TOP);  
  2987.             a.recycle();  
  2988.         }  
  2989.     }  
  2990.   
  2991.     static class ViewPositionComparator implements Comparator<View> {  
  2992.         @Override  
  2993.         public int compare(View lhs, View rhs) {  
  2994.             final LayoutParams llp = (LayoutParams) lhs.getLayoutParams();  
  2995.             final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams();  
  2996.             if (llp.isDecor != rlp.isDecor) {  
  2997.                 return llp.isDecor ? 1 : -1;  
  2998.             }  
  2999.             return llp.position - rlp.position;  
  3000.         }  
  3001.     }  
  3002. }  
适配器代码:

[java]  view plain  copy
 print ?
  1. package com.yymonkeydo.androiddemo;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.support.v4.app.Fragment;  
  6. import android.support.v4.app.FragmentManager;  
  7. import android.support.v4.app.FragmentStatePagerAdapter;  
  8.   
  9. public class VerticalPagerAdapter extends FragmentStatePagerAdapter {  
  10.   
  11.     private List<Fragment> mData;  
  12.   
  13.     public VerticalPagerAdapter(FragmentManager fm, List<Fragment> data) {  
  14.         super(fm);  
  15.         mData = data;  
  16.     }  
  17.   
  18.     @Override  
  19.     public Fragment getItem(int position) {  
  20.         return mData.get(position);  
  21.     }  
  22.   
  23.     @Override  
  24.     public int getCount() {  
  25.         return mData == null ? 0 : mData.size();  
  26.     }  
  27.   
  28. }  

Fragment代码:

[java]  view plain  copy
 print ?
  1. package com.yymonkeydo.androiddemo;  
  2.   
  3. import android.os.Bundle;  
  4. import android.support.v4.app.Fragment;  
  5. import android.view.Gravity;  
  6. import android.view.LayoutInflater;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.Button;  
  10.   
  11. public class MyFragment extends Fragment {  
  12.     @Override  
  13.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  14.             Bundle savedInstanceState) {  
  15.         Button btn = new Button(getActivity());  
  16.         btn.setText("TxT");  
  17.         btn.setGravity(Gravity.CENTER);  
  18.         return btn;  
  19.     }  
  20. }  


Activity:

[java]  view plain  copy
 print ?
  1. package com.yymonkeydo.androiddemo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import com.yymonkeydo.androiddemo.R;  
  7.   
  8. import android.os.Bundle;  
  9. import android.support.v4.app.Fragment;  
  10. import android.support.v4.app.FragmentActivity;  
  11.   
  12. public class MainActivity extends FragmentActivity {  
  13.     private VerticalViewPager mViewPager;  
  14.     private VerticalPagerAdapter mAdapter;  
  15.     private List<Fragment> mData;  
  16.   
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.activity_main);  
  21.         mViewPager = (VerticalViewPager) findViewById(R.id.viewpager);  
  22.         mData = new ArrayList<Fragment>();  
  23.         mData.add(new MyFragment());  
  24.         mData.add(new MyFragment());  
  25.         mData.add(new MyFragment());  
  26.         mAdapter = new VerticalPagerAdapter(getSupportFragmentManager(), mData);  
  27.         mViewPager.setAdapter(mAdapter);  
  28.     }  
  29.   
  30. }  
上面代码直接用回报错,把 VerticalViewPager 类中的 FloatMath改成Math就行了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值